	////////////////////////////////
	// Directives
	///////////////////////////////

	function vxSetupDirectives() {
		vx.module('v').directive({
			a : htmlAnchorDirective,
			input : inputDirective,
			textarea : inputDirective,
			select : selectDirective,
			option : optionDirective,
			button : inputDirective,
			//vVal : vValDirective,
			form : formDirective,
			script : scriptDirective,
			//style : styleDirective,

			//vCsp : vCspDirective,
			vBind : vBindDirective,
			//vBindHtml : vBindHtmlDirective,
			//vBindTemplate : vBindTemplateDirective,
			//vClass : vClassDirective,
			//vClassEven : vClassEvenDirective,
			//vClassOdd : vClassOddDirective,
			//vCloak : vCloakDirective,
			vController : vControllerDirective,
			//vForm : vFormDirective,
			vHide : vHideDirective,
			vInclude : vIncludeDirective,
			vInit : vInitDirective,
			//vNonBindable : vNonBindableDirective,
			vRepeat : vRepeatDirective,
			vShow : vShowDirective,
			vSubmit : vSubmitDirective,
			//vStyle : vStyleDirective,
			vIf : vIfDirective,
			//vSwitch : vSwitchDirective,
			//vSwitchWhen : vSwitchWhenDirective,
			//vSwitchDefault : vSwitchDefaultDirective,
			vOptions : vOptionsDirective,
			//vTransclude : vTranscludeDirective,
			vModel : vModelDirective,
			//vList : vListDirective,
			vChange : vChangeDirective,
			required : requiredDirective,
			vRequired : requiredDirective,
			//vValue : vValueDirective,
			vViewport : vViewportDirective,
			vPage : vPageDirective,
			vViewSetup : vViewSetupDirective,
			//vTarget : vTargetDirective,
			//vTrack : vTrackDirective
		}).directive(vEventDirectives).directive(vAttributeAliasDirectives);
	}

	/**
	 * @vxdoc directive
	 * @name vx.directive:vCsp
	 * @priority 1000
	 *
	 * @element html
	 * @description
	 * Enables [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) support.
	 *
	 * This is necessary when developing things like Google Chrome Extensions.
	 *
	 * CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things).
	 * For us to be compatible, we just need to implement the "getterFn" in $parse without violating
	 * any of these restrictions.
	 *
	 * vx uses `Function(string)` generated functions as a speed optimization. By applying `vCsp`
	 * it is be possible to opt into the CSP compatible mode. When this mode is on, vx will
	 * evaluate all expressions up to 30% slower than in non-CSP mode, but no security violations will
	 * be raised.
	 *
	 * In order to use this feature put `vCsp` directive on the root element of the application.
	 *
	 * @example
	 * This example shows how to apply the `vCsp` directive to the `html` tag.
	 <pre>
	 <!doctype html>
	 <html v-app v-csp>
	 ...
	 ...
	 </html>
	 </pre>
	 */
	/*
	vCspDirective.$inject = ['$sniffer'];
	function vCspDirective($sniffer) {
		return {
			priority : 1000,
			compile : function() {
				$sniffer.csp = true;
			}
		};
	}
	*/

	/**
	 * @vxdoc directive
	 * @name vx.directive:vInit
	 *
	 * @description
	 * The `vInit` directive specifies initialization tasks to be executed
	 *  before the template enters execution mode during bootstrap.
	 *
	 * @element ANY
	 * @param {expression} vInit {@link guide/expression Expression} to eval.
	 *
	 * @example
	 <doc:example>
	 <doc:source>
	 <div v-init="greeting='Hello'; person='World'">
	 {{greeting}} {{person}}!
	 </div>
	 </doc:source>
	 <doc:scenario>
	 it('should check greeting', function() {
	 expect(binding('greeting')).toBe('Hello');
	 expect(binding('person')).toBe('World');
	 });
	 </doc:scenario>
	 </doc:example>
	 */
	vInitDirective.$inject = ['$$remote'];
	function vInitDirective($$remote) {
		return {
			restrict : 'AC',
			compile : function() {
				return {
					pre : function(scope, element, attrs) {
						scope.$eval(attrs.vInit, injectRemote(element, null, attrs.vInit, false, $$remote));
					}
				};
			}
		};
	}

	/**
	 * @vxdoc directive
	 * @name vx.directive:vController
	 *
	 * @description
	 * The `vController` directive assigns behavior to a scope. This is a key aspect of how vx
	 * supports the principles behind the Model-View-Controller design pattern.
	 *
	 * MVC components in vx:
	 *
	 * * Model — The Model is data in scope properties; scopes are attached to the DOM.
	 * * View — The template (HTML with data bindings) is rendered into the View.
	 * * Controller — The `vController` directive specifies a Controller class; the class has
	 *   methods that typically express the business logic behind the application.
	 *
	 * Note that an alternative way to define controllers is via the {@link vx.$route}
	 * service.
	 *
	 * @element ANY
	 * @scope
	 * @param {expression} vController Name of a globally accessible constructor function or an
	 *     {@link guide/expression expression} that on the current scope evaluates to a
	 *     constructor function. The controller instance can further be published into the scope
	 *     by adding `as localName` the controller name attribute.
	 *
	 * @example
	 * Here is a simple form for editing user contact information. Adding, removing, clearing, and
	 * greeting are methods declared on the controller (see source tab). These methods can
	 * easily be called from the vx markup. Notice that the scope becomes the `this` for the
	 * controller's instance. This allows for easy access to the view data from the controller. Also
	 * notice that any changes to the data are automatically reflected in the View without the need
	 * for a manual update.
	 <doc:example>
	 <doc:source>
	 <script>
	 function SettingsController1() {
	 this.name = "John Smith";
	 this.contacts = [
	 {type: 'phone', value: '408 555 1212'},
	 {type: 'email', value: 'john.smith@example.org'} ];
	 };

	 SettingsController1.prototype.greet = function() {
	 alert(this.name);
	 };

	 SettingsController1.prototype.addContact = function() {
	 this.contacts.push({type: 'email', value: 'yourname@example.org'});
	 };

	 SettingsController1.prototype.removeContact = function(contactToRemove) {
	 var index = this.contacts.indexOf(contactToRemove);
	 this.contacts.splice(index, 1);
	 };

	 SettingsController1.prototype.clearContact = function(contact) {
	 contact.type = 'phone';
	 contact.value = '';
	 };
	 </script>
	 <div id="ctrl-as-exmpl" v-controller="SettingsController1 as settings">
	 Name: <input type="text" v-model="settings.name"/>
	 [ <a href="" v-click="settings.greet()">greet</a> ]<br/>
	 Contact:
	 <ul>
	 <li v-repeat="contact in settings.contacts">
	 <select v-model="contact.type">
	 <option>phone</option>
	 <option>email</option>
	 </select>
	 <input type="text" v-model="contact.value"/>
	 [ <a href="" v-click="settings.clearContact(contact)">clear</a>
	 | <a href="" v-click="settings.removeContact(contact)">X</a> ]
	 </li>
	 <li>[ <a href="" v-click="settings.addContact()">add</a> ]</li>
	 </ul>
	 </div>
	 </doc:source>
	 <doc:scenario>
	 it('should check controller as', function() {
	 expect(element('#ctrl-as-exmpl>:input').val()).toBe('John Smith');
	 expect(element('#ctrl-as-exmpl li:nth-child(1) input').val())
	 .toBe('408 555 1212');
	 expect(element('#ctrl-as-exmpl li:nth-child(2) input').val())
	 .toBe('john.smith@example.org');

	 element('#ctrl-as-exmpl li:first a:contains("clear")').click();
	 expect(element('#ctrl-as-exmpl li:first input').val()).toBe('');

	 element('#ctrl-as-exmpl li:last a:contains("add")').click();
	 expect(element('#ctrl-as-exmpl li:nth-child(3) input').val())
	 .toBe('yourname@example.org');
	 });
	 </doc:scenario>
	 </doc:example>
	 <doc:example>
	 <doc:source>
	 <script>
	 function SettingsController2($scope) {
	 $scope.name = "John Smith";
	 $scope.contacts = [
	 {type:'phone', value:'408 555 1212'},
	 {type:'email', value:'john.smith@example.org'} ];

	 $scope.greet = function() {
	 alert(this.name);
	 };

	 $scope.addContact = function() {
	 this.contacts.push({type:'email', value:'yourname@example.org'});
	 };

	 $scope.removeContact = function(contactToRemove) {
	 var index = this.contacts.indexOf(contactToRemove);
	 this.contacts.splice(index, 1);
	 };

	 $scope.clearContact = function(contact) {
	 contact.type = 'phone';
	 contact.value = '';
	 };
	 }
	 </script>
	 <div id="ctrl-exmpl" v-controller="SettingsController2">
	 Name: <input type="text" v-model="name"/>
	 [ <a href="" v-click="greet()">greet</a> ]<br/>
	 Contact:
	 <ul>
	 <li v-repeat="contact in contacts">
	 <select v-model="contact.type">
	 <option>phone</option>
	 <option>email</option>
	 </select>
	 <input type="text" v-model="contact.value"/>
	 [ <a href="" v-click="clearContact(contact)">clear</a>
	 | <a href="" v-click="removeContact(contact)">X</a> ]
	 </li>
	 <li>[ <a href="" v-click="addContact()">add</a> ]</li>
	 </ul>
	 </div>
	 </doc:source>
	 <doc:scenario>
	 it('should check controller', function() {
	 expect(element('#ctrl-exmpl>:input').val()).toBe('John Smith');
	 expect(element('#ctrl-exmpl li:nth-child(1) input').val())
	 .toBe('408 555 1212');
	 expect(element('#ctrl-exmpl li:nth-child(2) input').val())
	 .toBe('john.smith@example.org');

	 element('#ctrl-exmpl li:first a:contains("clear")').click();
	 expect(element('#ctrl-exmpl li:first input').val()).toBe('');

	 element('#ctrl-exmpl li:last a:contains("add")').click();
	 expect(element('#ctrl-exmpl li:nth-child(3) input').val())
	 .toBe('yourname@example.org');
	 });
	 </doc:scenario>
	 </doc:example>

	 */
	function vControllerDirective() {
		return {
			scope : true,
			controller : '@'//XXX use attr v-controller as name
		};
	}

	/**
	 * @vxdoc directive
	 * @name vx.directive:vBind
	 *
	 * @description
	 * The `vBind` attribute tells VX to replace the text content of the specified HTML element
	 * with the value of a given expression, and to update the text content when the value of that
	 * expression changes.
	 *
	 * Typically, you don't use `vBind` directly, but instead you use the double curly markup like
	 * `{{ expression }}` which is similar but less verbose.
	 *
	 * One scenario in which the use of `vBind` is preferred over `{{ expression }}` binding is when
	 * it's desirable to put bindings into template that is momentarily displayed by the browser in its
	 * raw state before VX compiles it. Since `vBind` is an element attribute, it makes the
	 * bindings invisible to the user while the page is loading.
	 *
	 * An alternative solution to this problem would be using the
	 * {@link vx.directive:vCloak vCloak} directive.
	 *
	 *
	 * @element ANY
	 * @param {expression} vBind {@link guide/expression Expression} to evaluate.
	 *
	 * @example
	 * Enter a name in the Live Preview text box; the greeting below the text box changes instantly.
	 <doc:example>
	 <doc:source>
	 <script>
	 function Ctrl($scope) {
	 $scope.name = 'Whirled';
	 }
	 </script>
	 <div v-controller="Ctrl">
	 Enter name: <input type="text" v-model="name"><br>
	 Hello <span v-bind="name"></span>!
	 </div>
	 </doc:source>
	 <doc:scenario>
	 it('should check v-bind', function() {
	 expect(using('.doc-example-live').binding('name')).toBe('Whirled');
	 using('.doc-example-live').input('name').enter('world');
	 expect(using('.doc-example-live').binding('name')).toBe('world');
	 });
	 </doc:scenario>
	 </doc:example>
	 */
	function vBindDirective() {
		return {
			restrict : 'AC',
			link : function(scope, element, attr) {
				element.addClass('v-binding').data('$binding', attr.vBind);
				scope.$watch(attr.vBind, function vBindWatchAction(value) {
					element.text(value === undefined ? '' : value);
				});
			}
		};
	}
	
	/**
	 * @vxdoc directive
	 * @name vx.directive:vBindHtml
	 *
	 * @description
	 * Creates a binding that will innerHTML the result of evaluating the `expression` into the current
	 * element. *The innerHTML-ed content will not be sanitized!* You should use this directive only if
	 * {@link vSanitize.directive:vBindHtml vBindHtml} directive is too
	 * restrictive and when you absolutely trust the source of the content you are binding to.
	 *
	 * See {@link vSanitize.$sanitize $sanitize} docs for examples.
	 *
	 * @element ANY
	 * @param {expression} vBindHtml {@link guide/expression Expression} to evaluate.
	 */
	/*
	function vBindHtmlDirective() {
		return function(scope, element, attr) {
			element.addClass('v-binding').data('$binding', attr.vBindHtml);
			scope.$watch(attr.vBindHtml, function vBindHtmlWatchAction(value) {
				element.html(value || '');
			});
		};
	}
	*/

	/**
	 * @vxdoc directive
	 * @name vx.directive:vBindTemplate
	 *
	 * @description
	 * The `vBindTemplate` directive specifies that the element
	 * text should be replaced with the template in vBindTemplate.
	 * Unlike vBind the vBindTemplate can contain multiple `{{` `}}`
	 * expressions. (This is required since some HTML elements
	 * can not have SPAN elements such as TITLE, or OPTION to name a few.)
	 *
	 * @element ANY
	 * @param {string} vBindTemplate template of form
	 *   <tt>{{</tt> <tt>expression</tt> <tt>}}</tt> to eval.
	 *
	 * @example
	 * Try it here: enter text in text box and watch the greeting change.
	 <doc:example>
	 <doc:source>
	 <script>
	 function Ctrl($scope) {
	 $scope.salutation = 'Hello';
	 $scope.name = 'World';
	 }
	 </script>
	 <div v-controller="Ctrl">
	 Salutation: <input type="text" v-model="salutation"><br>
	 Name: <input type="text" v-model="name"><br>
	 <pre v-bind-template="{{salutation}} {{name}}!"></pre>
	 </div>
	 </doc:source>
	 <doc:scenario>
	 it('should check v-bind', function() {
	 expect(using('.doc-example-live').binding('salutation')).
	 toBe('Hello');
	 expect(using('.doc-example-live').binding('name')).
	 toBe('World');
	 using('.doc-example-live').input('salutation').enter('Greetings');
	 using('.doc-example-live').input('name').enter('user');
	 expect(using('.doc-example-live').binding('salutation')).
	 toBe('Greetings');
	 expect(using('.doc-example-live').binding('name')).
	 toBe('user');
	 });
	 </doc:scenario>
	 </doc:example>
	 */
	/*
	vBindTemplateDirective.$inject = ['$interpolate'];
	function vBindTemplateDirective($interpolate) {
		return function(scope, element, attr) {
			// TODO: move this to scenario runner
			var interpolateFn = $interpolate(element.attr(attr.$attr.vBindTemplate));
			element.addClass('v-binding').data('$binding', interpolateFn);
			attr.$observe('vBindTemplate', function(value) {
				element.text(value);
			});
		};
	}
	*/

	/**
	 * @vxdoc directive
	 * @name vx.directive:vClick
	 *
	 * @description
	 * The vClick allows you to specify custom behavior when
	 * element is clicked.
	 *
	 * @element ANY
	 * @param {expression} vClick {@link guide/expression Expression} to evaluate upon
	 * click. (Event object is available as `$event`)
	 *
	 * @example
	 <doc:example>
	 <doc:source>
	 <button v-click="count = count + 1" v-init="count=0">
	 Increment
	 </button>
	 count: {{count}}
	 </doc:source>
	 <doc:scenario>
	 it('should check v-click', function() {
	 expect(binding('count')).toBe('0');
	 element('.doc-example-live :button').click();
	 expect(binding('count')).toBe('1');
	 });
	 </doc:scenario>
	 </doc:example>
	 */
	/**
	 * @vxdoc directive
	 * @name vx.directive:vDblclick
	 *
	 * @description
	 * The `vDblclick` directive allows you to specify custom behavior on dblclick event.
	 *
	 * @element ANY
	 * @param {expression} vDblclick {@link guide/expression Expression} to evaluate upon
	 * dblclick. (Event object is available as `$event`)
	 *
	 * @example
	 * See {@link vx.directive:vClick vClick}
	 */

	/**
	 * @vxdoc directive
	 * @name vx.directive:vMousedown
	 *
	 * @description
	 * The vMousedown directive allows you to specify custom behavior on mousedown event.
	 *
	 * @element ANY
	 * @param {expression} vMousedown {@link guide/expression Expression} to evaluate upon
	 * mousedown. (Event object is available as `$event`)
	 *
	 * @example
	 * See {@link vx.directive:vClick vClick}
	 */

	/**
	 * @vxdoc directive
	 * @name vx.directive:vMouseup
	 *
	 * @description
	 * Specify custom behavior on mouseup event.
	 *
	 * @element ANY
	 * @param {expression} vMouseup {@link guide/expression Expression} to evaluate upon
	 * mouseup. (Event object is available as `$event`)
	 *
	 * @example
	 * See {@link vx.directive:vClick vClick}
	 */

	/**
	 * @vxdoc directive
	 * @name vx.directive:vMouseover
	 *
	 * @description
	 * Specify custom behavior on mouseover event.
	 *
	 * @element ANY
	 * @param {expression} vMouseover {@link guide/expression Expression} to evaluate upon
	 * mouseover. (Event object is available as `$event`)
	 *
	 * @example
	 * See {@link vx.directive:vClick vClick}
	 */

	/**
	 * @vxdoc directive
	 * @name vx.directive:vMouseenter
	 *
	 * @description
	 * Specify custom behavior on mouseenter event.
	 *
	 * @element ANY
	 * @param {expression} vMouseenter {@link guide/expression Expression} to evaluate upon
	 * mouseenter. (Event object is available as `$event`)
	 *
	 * @example
	 * See {@link vx.directive:vClick vClick}
	 */

	/**
	 * @vxdoc directive
	 * @name vx.directive:vMouseleave
	 *
	 * @description
	 * Specify custom behavior on mouseleave event.
	 *
	 * @element ANY
	 * @param {expression} vMouseleave {@link guide/expression Expression} to evaluate upon
	 * mouseleave. (Event object is available as `$event`)
	 *
	 * @example
	 * See {@link vx.directive:vClick vClick}
	 */

	/**
	 * @vxdoc directive
	 * @name vx.directive:vMousemove
	 *
	 * @description
	 * Specify custom behavior on mousemove event.
	 *
	 * @element ANY
	 * @param {expression} vMousemove {@link guide/expression Expression} to evaluate upon
	 * mousemove. (Event object is available as `$event`)
	 *
	 * @example
	 * See {@link vx.directive:vClick vClick}
	 */

	/**
	 * @vxdoc directive
	 * @name v.directive:vKeydown
	 *
	 * @description
	 * Specify custom behavior on keydown event.
	 *
	 * @element ANY
	 * @param {expression} vKeydown {@link guide/expression Expression} to evaluate upon
	 * keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
	 *
	 * @example
	 * See {@link v.directive:vClick vClick}
	 */

	/**
	 * @vxdoc directive
	 * @name v.directive:vKeyup
	 *
	 * @description
	 * Specify custom behavior on keyup event.
	 *
	 * @element ANY
	 * @param {expression} vKeyup {@link guide/expression Expression} to evaluate upon
	 * keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
	 *
	 * @example
	 * See {@link v.directive:vClick vClick}
	 */

	var EVENTS = 'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress';
	var vEventDirectives = {};
	forEach((EVENTS).split(' '), function(name) {
		var directiveName = directiveNormalize('v-' + name);
		vEventDirectives[directiveName] = ['$parse', '$$remote', '$browser',
		function($parse, $$remote, $browser) {
			return function(scope, element, attr) {
				var fn = $parse(attr[directiveName]), eventName = lowercase(name);
				var await = attr.await ? int(attr.await) : 0;
				var eventhandler = function(event) {
					scope.$apply(function() {
						fn(scope, injectRemote(element, {
							$event : event
						}, attr[directiveName], false, $$remote));
					}, directiveName);
				};
				if (await)
					eventhandler = $browser.debounce(eventhandler, await);
				element.bind(eventName, function handler(event) {
					var target = event.target;
					//XXX maybe need more justify it ???
					if (target !== element[0]) {// process Propagated event
						var tname = _nodeName(target);
						// skip input elements bubbles
						if (tname === 'INPUT' || tname === 'TEXTAREA' || tname === 'BUTTON' || tname === 'SELECT' || tname === 'OPTION')
							return;
					}

					eventhandler(event);

					//TODO: how to deal with $locationProvider's $document.bind('click', function(event)...)
					// in Chrome 7.0.xxxx.0, click in form lead reload
					var nn = _nodeName(element);
					if (nn == 'A') {
						//event.stopPropagation();
						event.preventDefault();
					}
				});
			};
		}];

	});
	/**
	 * @vxdoc directive
	 * @name vx.directive:vSubmit
	 *
	 * @description
	 * Enables binding vx expressions to onsubmit events.
	 *
	 * Additionally it prevents the default action (which for form means sending the request to the
	 * server and reloading the current page).
	 *
	 * @element form
	 * @param {expression} vSubmit {@link guide/expression Expression} to eval.
	 *
	 * @example
	 <doc:example>
	 <doc:source>
	 <script>
	 function Ctrl($scope) {
	 $scope.list = [];
	 $scope.text = 'hello';
	 $scope.submit = function() {
	 if (this.text) {
	 this.list.push(this.text);
	 this.text = '';
	 }
	 };
	 }
	 </script>
	 <form v-submit="submit()" v-controller="Ctrl">
	 Enter text and hit enter:
	 <input type="text" v-model="text" name="text" />
	 <input type="submit" id="submit" value="Submit" />
	 <pre>list={{list}}</pre>
	 </form>
	 </doc:source>
	 <doc:scenario>
	 it('should check v-submit', function() {
	 expect(binding('list')).toBe('[]');
	 element('.doc-example-live #submit').click();
	 expect(binding('list')).toBe('["hello"]');
	 expect(input('text').val()).toBe('');
	 });
	 it('should ignore empty strings', function() {
	 expect(binding('list')).toBe('[]');
	 element('.doc-example-live #submit').click();
	 element('.doc-example-live #submit').click();
	 expect(binding('list')).toBe('["hello"]');
	 });
	 </doc:scenario>
	 </doc:example>
	 */
	vSubmitDirective.$inject = ['$parse', '$$remote'];
	function vSubmitDirective($parse, $$remote) {
		return {
			require : 'form',
			link : function(scope, element, attrs, ctrl) {
				var fn = $parse(attrs.vSubmit), parent = attrs.parent === 'true';
				element.bind('submit', function(event) {
					var formCtrl = ctrl;
					// forbid cascade submit
					if (event.target !== element[0]) {
						var formCtrl0 = jqLite(event.target).controller('form');
						if (formCtrl !== formCtrl0)
							return;
					}
					if (!formCtrl.$getError(parent)) {
						//scope.$apply(function() {
						fn(scope, injectRemote(element, {
							$event : event,
							$data : formCtrl.$getData(parent)
						}, attrs.vSubmit, true, $$remote));
						//}, 'v-submit');
					}
					//event.stopPropagation();
					event.preventDefault();
				});
			}
		};

	}

	/**
	 * class helper method
	 */
	function classDirective(name, selector) {
		name = 'vClass' + name;
		return function() {
			return {
				restrict : 'AC',
				link : linker
			};
		};
		function linker(scope, element, attr) {
			var oldVal;
			scope.$watch(attr[name], vClassWatchAction, true);
			attr.$observe('class', function(value) {
				var vClass = scope.$eval(attr[name]);
				vClassWatchAction(vClass, vClass);
			});
			if (name !== 'vClass') {
				scope.$watch('$index', function($index, old$index) {
					var mod = $index % 2;
					if (mod !== old$index % 2) {
						if (mod === selector) {
							addClass(scope.$eval(attr[name]));
						} else {
							removeClass(scope.$eval(attr[name]));
						}
					}
				});
			}

			function vClassWatchAction(newVal, oldVal) {
				if (selector === true || scope.$index % 2 === selector) {
					if (oldVal && !equals(newVal, oldVal)) {
						removeClass(oldVal);
					}
					addClass(newVal);
				}
				oldVal = copy(newVal);
			}

			function removeClass(classVal) {
				if (isObject(classVal) && !isArray(classVal)) {
					classVal = map(classVal, function(v, k) {
						if (v)
							return k;
					});
				}
				element.removeClass(isArray(classVal) ? classVal.join(' ') : classVal);
			}

			function addClass(classVal) {
				if (isObject(classVal) && !isArray(classVal)) {
					classVal = map(classVal, function(v, k) {
						if (v)
							return k;
					});
				}
				if (classVal) {
					element.addClass(isArray(classVal) ? classVal.join(' ') : classVal);
				}
			}

		}

	}

	/**
	 * @vxdoc directive
	 * @name vx.directive:vClass
	 *
	 * @description
	 * The `vClass` allows you to set CSS class on HTML element dynamically by databinding an
	 * expression that represents all classes to be added.
	 *
	 * The directive won't add duplicate classes if a particular class was already set.
	 *
	 * When the expression changes, the previously added classes are removed and only then the
	 * new classes are added.
	 *
	 * @element ANY
	 * @param {expression} vClass {@link guide/expression Expression} to eval. The result
	 *   of the evaluation can be a string representing space delimited class
	 *   names, an array, or a map of class names to boolean values.
	 *
	 * @example
	 <example>
	 <file name="index.html">
	 <input type="button" value="set" v-click="myVar='my-class'">
	 <input type="button" value="clear" v-click="myVar=''">
	 <br>
	 <span v-class="myVar">Sample Text</span>
	 </file>
	 <file name="style.css">
	 .my-class {
	 color: red;
	 }
	 </file>
	 <file name="scenario.js">
	 it('should check v-class', function() {
	 expect(element('.doc-example-live span').prop('className')).not().
	 toMatch(/my-class/);

	 using('.doc-example-live').element(':button:first').click();

	 expect(element('.doc-example-live span').prop('className')).
	 toMatch(/my-class/);

	 using('.doc-example-live').element(':button:last').click();

	 expect(element('.doc-example-live span').prop('className')).not().
	 toMatch(/my-class/);
	 });
	 </file>
	 </example>
	 */
	//var vClassDirective = classDirective('', true);

	/**
	 * @vxdoc directive
	 * @name vx.directive:vClassOdd
	 *
	 * @description
	 * The `vClassOdd` and `vClassEven` directives work exactly as
	 * {@link vx.directive:vClass vClass}, except it works in
	 * conjunction with `vRepeat` and takes affect only on odd (even) rows.
	 *
	 * This directive can be applied only within a scope of an
	 * {@link vx.directive:vRepeat vRepeat}.
	 *
	 * @element ANY
	 * @param {expression} vClassOdd {@link guide/expression Expression} to eval. The result
	 *   of the evaluation can be a string representing space delimited class names or an array.
	 *
	 * @example
	 <example>
	 <file name="index.html">
	 <ol v-init="names=['John', 'Mary', 'Cate', 'Suz']">
	 <li v-repeat="name in names">
	 <span v-class-odd="'odd'" v-class-even="'even'">
	 {{name}}
	 </span>
	 </li>
	 </ol>
	 </file>
	 <file name="style.css">
	 .odd {
	 color: red;
	 }
	 .even {
	 color: blue;
	 }
	 </file>
	 <file name="scenario.js">
	 it('should check v-class-odd and v-class-even', function() {
	 expect(element('.doc-example-live li:first span').prop('className')).
	 toMatch(/odd/);
	 expect(element('.doc-example-live li:last span').prop('className')).
	 toMatch(/even/);
	 });
	 </file>
	 </example>
	 */
	//var vClassOddDirective = classDirective('Odd', 0);

	/**
	 * @vxdoc directive
	 * @name vx.directive:vClassEven
	 *
	 * @description
	 * The `vClassOdd` and `vClassEven` directives work exactly as
	 * {@link vx.directive:vClass vClass}, except it works in
	 * conjunction with `vRepeat` and takes affect only on odd (even) rows.
	 *
	 * This directive can be applied only within a scope of an
	 * {@link vx.directive:vRepeat vRepeat}.
	 *
	 * @element ANY
	 * @param {expression} vClassEven {@link guide/expression Expression} to eval. The
	 *   result of the evaluation can be a string representing space delimited class names or an array.
	 *
	 * @example
	 <example>
	 <file name="index.html">
	 <ol v-init="names=['John', 'Mary', 'Cate', 'Suz']">
	 <li v-repeat="name in names">
	 <span v-class-odd="'odd'" v-class-even="'even'">
	 {{name}} &nbsp; &nbsp; &nbsp;
	 </span>
	 </li>
	 </ol>
	 </file>
	 <file name="style.css">
	 .odd {
	 color: red;
	 }
	 .even {
	 color: blue;
	 }
	 </file>
	 <file name="scenario.js">
	 it('should check v-class-odd and v-class-even', function() {
	 expect(element('.doc-example-live li:first span').prop('className')).
	 toMatch(/odd/);
	 expect(element('.doc-example-live li:last span').prop('className')).
	 toMatch(/even/);
	 });
	 </file>
	 </example>
	 */
	//var vClassEvenDirective = classDirective('Even', 1);

	/**
	 * @vxdoc directive
	 * @name vx.directive:vShow
	 *
	 * @description
	 * The `vShow` and `vHide` directives show or hide a portion of the DOM tree (HTML)
	 * conditionally based on **"truthy"** values evaluated within an {expression}. In other
	 * words, if the expression assigned to **vShow evaluates to a true value** then **the element is set to visible**
	 * (via `display:block` in css) and **if false** then **the element is set to hidden** (so display:none).
	 * With vHide this is the reverse whereas true values cause the element itself to become
	 * hidden.
	 *
	 * Additionally, you can also provide animations via the vAnimate attribute to animate the **show**
	 * and **hide** effects.
	 *
	 * @animations
	 * show - happens after the vShow expression evaluates to a truthy value and the contents are set to visible
	 * hide - happens before the vShow expression evaluates to a non truthy value and just before the contents are set to hidden

	 *
	 * @element ANY
	 * @param {expression} vShow If the {@link guide/expression expression} is truthy
	 *     then the element is shown or hidden respectively.
	 *
	 * @example
	 <example animations="true">
	 <file name="index.html">
	 Click me: <input type="checkbox" v-model="checked"><br/>
	 <div>
	 Show:
	 <span class="check-element"
	 v-show="checked"
	 v-animate="{show: 'example-show', hide: 'example-hide'}">
	 <span class="icon-thumbs-up"></span> I show up when your checkbox is checked.
	 </span>
	 </div>
	 <div>
	 Hide:
	 <span class="check-element"
	 v-hide="checked"
	 v-animate="{show: 'example-show', hide: 'example-hide'}">
	 <span class="icon-thumbs-down"></span> I hide when your checkbox is checked.
	 </span>
	 </div>
	 </file>
	 <file name="animations.css">
	 .example-show, .example-hide {
	 -webkit-transition:all linear 0.5s;
	 -moz-transition:all linear 0.5s;
	 -ms-transition:all linear 0.5s;
	 -o-transition:all linear 0.5s;
	 transition:all linear 0.5s;
	 }

	 .example-show {
	 line-height:0;
	 opacity:0;
	 padding:0 10px;
	 }
	 .example-show-active.example-show-active {
	 line-height:20px;
	 opacity:1;
	 padding:10px;
	 border:1px solid black;
	 background:white;
	 }

	 .example-hide {
	 line-height:20px;
	 opacity:1;
	 padding:10px;
	 border:1px solid black;
	 background:white;
	 }
	 .example-hide-active.example-hide-active {
	 line-height:0;
	 opacity:0;
	 padding:0 10px;
	 }

	 .check-element {
	 padding:10px;
	 border:1px solid black;
	 background:white;
	 }
	 </file>
	 <file name="scenario.js">
	 it('should check v-show / v-hide', function() {
	 expect(element('.doc-example-live span:first:hidden').count()).toEqual(1);
	 expect(element('.doc-example-live span:last:visible').count()).toEqual(1);

	 input('checked').check();

	 expect(element('.doc-example-live span:first:visible').count()).toEqual(1);
	 expect(element('.doc-example-live span:last:hidden').count()).toEqual(1);
	 });
	 </file>
	 </example>
	 */
	//TODO(misko): refactor to remove element from the DOM
	vShowDirective.$inject = ['$animator'];
	function vShowDirective($animator) {
		return {
			restrict : 'AC',
			link : function(scope, element, attr) {
				var animate = $animator(scope, attr);
				scope.$watch(attr.vShow, function vShowWatchAction(value) {
					animate[toBoolean(value) ? 'show' : 'hide'](element);
				});
			}
		};
	}

	/**
	 * @vxdoc directive
	 * @name vx.directive:vHide
	 *
	 * @description
	 * The `vHide` and `vShow` directives hide or show a portion of the DOM tree (HTML)
	 * conditionally based on **"truthy"** values evaluated within an {expression}. In other
	 * words, if the expression assigned to **vShow evaluates to a true value** then **the element is set to visible**
	 * (via `display:block` in css) and **if false** then **the element is set to hidden** (so display:none).
	 * With vHide this is the reverse whereas true values cause the element itself to become
	 * hidden.
	 *
	 * Additionally, you can also provide animations via the vAnimate attribute to animate the **show**
	 * and **hide** effects.
	 *
	 * @animations
	 * show - happens after the vHide expression evaluates to a non truthy value and the contents are set to visible
	 * hide - happens after the vHide expression evaluates to a truthy value and just before the contents are set to hidden
	 *
	 * @element ANY
	 * @param {expression} vHide If the {@link guide/expression expression} is truthy then
	 *     the element is shown or hidden respectively.
	 *
	 * @example
	 <example animations="true">
	 <file name="index.html">
	 Click me: <input type="checkbox" v-model="checked"><br/>
	 <div>
	 Show:
	 <span class="check-element"
	 v-show="checked"
	 v-animate="{show: 'example-show', hide: 'example-hide'}">
	 <span class="icon-thumbs-up"></span> I show up when your checkbox is checked.
	 </span>
	 </div>
	 <div>
	 Hide:
	 <span class="check-element"
	 v-hide="checked"
	 v-animate="{show: 'example-show', hide: 'example-hide'}">
	 <span class="icon-thumbs-down"></span> I hide when your checkbox is checked.
	 </span>
	 </div>
	 </file>
	 <file name="animations.css">
	 .example-show, .example-hide {
	 -webkit-transition:all linear 0.5s;
	 -moz-transition:all linear 0.5s;
	 -ms-transition:all linear 0.5s;
	 -o-transition:all linear 0.5s;
	 transition:all linear 0.5s;
	 }

	 .example-show {
	 line-height:0;
	 opacity:0;
	 padding:0 10px;
	 }
	 .example-show-active.example-show-active {
	 line-height:20px;
	 opacity:1;
	 padding:10px;
	 border:1px solid black;
	 background:white;
	 }

	 .example-hide {
	 line-height:20px;
	 opacity:1;
	 padding:10px;
	 border:1px solid black;
	 background:white;
	 }
	 .example-hide-active.example-hide-active {
	 line-height:0;
	 opacity:0;
	 padding:0 10px;
	 }

	 .check-element {
	 padding:10px;
	 border:1px solid black;
	 background:white;
	 }
	 </file>
	 <file name="scenario.js">
	 it('should check v-show / v-hide', function() {
	 expect(element('.doc-example-live .check-element:first:hidden').count()).toEqual(1);
	 expect(element('.doc-example-live .check-element:last:visible').count()).toEqual(1);

	 input('checked').check();

	 expect(element('.doc-example-live .check-element:first:visible').count()).toEqual(1);
	 expect(element('.doc-example-live .check-element:last:hidden').count()).toEqual(1);
	 });
	 </file>
	 </example>
	 */
	//TODO(misko): refactor to remove element from the DOM
	vHideDirective.$inject = ['$animator'];
	function vHideDirective($animator) {
		return {
			restrict : 'AC',
			link : function(scope, element, attr) {
				var animate = $animator(scope, attr);
				scope.$watch(attr.vHide, function vHideWatchAction(value) {
					animate[toBoolean(value) ? 'hide' : 'show'](element);
				});
			}
		};
	}

	/**
	 * @vxdoc directive
	 * @name vx.directive:vStyle
	 *
	 * @description
	 * The `vStyle` directive allows you to set CSS style on an HTML element conditionally.
	 *
	 * @element ANY
	 * @param {expression} vStyle {@link guide/expression Expression} which evals to an
	 *      object whose keys are CSS style names and values are corresponding values for those CSS
	 *      keys.
	 *
	 * @example
	 <example>
	 <file name="index.html">
	 <input type="button" value="set" v-click="myStyle={color:'red'}">
	 <input type="button" value="clear" v-click="myStyle={}">
	 <br/>
	 <span v-style="myStyle">Sample Text</span>
	 <pre>myStyle={{myStyle}}</pre>
	 </file>
	 <file name="style.css">
	 span {
	 color: black;
	 }
	 </file>
	 <file name="scenario.js">
	 it('should check v-style', function() {
	 expect(element('.doc-example-live span').css('color')).toBe('rgb(0, 0, 0)');
	 element('.doc-example-live :button[value=set]').click();
	 expect(element('.doc-example-live span').css('color')).toBe('rgb(255, 0, 0)');
	 element('.doc-example-live :button[value=clear]').click();
	 expect(element('.doc-example-live span').css('color')).toBe('rgb(0, 0, 0)');
	 });
	 </file>
	 </example>
	 */
	/*
	function vStyleDirective() {
		return {
			restrict : 'AC',
			link : function(scope, element, attr) {
				scope.$watch(attr.vStyle, function vStyleWatchAction(newStyles, oldStyles) {
					if (oldStyles && (newStyles !== oldStyles)) {
						forEach(oldStyles, function(val, style) {
							element.css(style, '');
						});
					}
					if (newStyles)
						element.css(newStyles);
				}, true);
			}
		};
	}
	*/

	/**
	 * @vxdoc directive
	 * @name vx.directive:vCloak
	 *
	 * @description
	 * The `vCloak` directive is used to prevent the VX html template from being briefly
	 * displayed by the browser in its raw (uncompiled) form while your application is loading. Use this
	 * directive to avoid the undesirable flicker effect caused by the html template display.
	 *
	 * The directive can be applied to the `<body>` element, but typically a fine-grained application is
	 * preferred in order to benefit from progressive rendering of the browser view.
	 *
	 * `vCloak` works in cooperation with a css rule that is embedded within `vx.js` and
	 *  `vx.min.js` files. Following is the css rule:
	 *
	 * <pre>
	 * [v\:cloak], [v-cloak], [data-v-cloak], [x-v-cloak], .v-cloak, .x-v-cloak {
	 *   display: none;
	 * }
	 * </pre>
	 *
	 * When this css rule is loaded by the browser, all html elements (including their children) that
	 * are tagged with the `v-cloak` directive are hidden. When VX comes across this directive
	 * during the compilation of the template it deletes the `vCloak` element attribute, which
	 * makes the compiled element visible.
	 *
	 * For the best result, `vx.js` script must be loaded in the head section of the html file;
	 * alternatively, the css rule (above) must be included in the external stylesheet of the
	 * application.
	 *
	 * Legacy browsers, like IE7, do not provide attribute selector support (added in CSS 2.1) so they
	 * cannot match the `[v\:cloak]` selector. To work around this limitation, you must add the css
	 * class `vCloak` in addition to `vCloak` directive as shown in the example below.
	 *
	 * @element ANY
	 *
	 * @example
	 <doc:example>
	 <doc:source>
	 <div id="template1" v-cloak>{{ 'hello' }}</div>
	 <div id="template2" v-cloak class="v-cloak">{{ 'hello IE7' }}</div>
	 </doc:source>
	 <doc:scenario>
	 it('should remove the template directive and css class', function() {
	 expect(element('.doc-example-live #template1').attr('v-cloak')).
	 not().toBeDefined();
	 expect(element('.doc-example-live #template2').attr('v-cloak')).
	 not().toBeDefined();
	 });
	 </doc:scenario>
	 </doc:example>
	 *
	 */
	/*
	function vCloakDirective() {
		return {
			restrict : 'AC',
			compile : function(element, attr) {
				attr.$set('vCloak', undefined);
				element.removeClass('v-cloak');
			}
		};
	}
	*/

	/**
	 * @vxdoc directive
	 * @name vx.directive:vDisabled
	 * @restrict A
	 *
	 * @description
	 *
	 * The following markup will make the button enabled on Chrome/Firefox but not on IE8 and older IEs:
	 * <pre>
	 * <div v-init="scope = { isDisabled: false }">
	 *  <button disabled="{{scope.isDisabled}}">Disabled</button>
	 * </div>
	 * </pre>
	 *
	 * The HTML specs do not require browsers to preserve the special attributes such as disabled.
	 * (The presence of them means true and absence means false)
	 * This prevents the vx compiler from correctly retrieving the binding expression.
	 * To solve this problem, we introduce the `vDisabled` directive.
	 *
	 * @example
	 <doc:example>
	 <doc:source>
	 Click me to toggle: <input type="checkbox" v-model="checked"><br/>
	 <button v-model="button" v-disabled="checked">Button</button>
	 </doc:source>
	 <doc:scenario>
	 it('should toggle button', function() {
	 expect(element('.doc-example-live :button').prop('disabled')).toBeFalsy();
	 input('checked').check();
	 expect(element('.doc-example-live :button').prop('disabled')).toBeTruthy();
	 });
	 </doc:scenario>
	 </doc:example>
	 *
	 * @element INPUT
	 * @param {expression} vDisabled VX expression that will be evaluated.
	 */

	/**
	 * @vxdoc directive
	 * @name vx.directive:vChecked
	 * @restrict A
	 *
	 * @description
	 * The HTML specs do not require browsers to preserve the special attributes such as checked.
	 * (The presence of them means true and absence means false)
	 * This prevents the vx compiler from correctly retrieving the binding expression.
	 * To solve this problem, we introduce the `vChecked` directive.
	 * @example
	 <doc:example>
	 <doc:source>
	 Check me to check both: <input type="checkbox" v-model="master"><br/>
	 <input id="checkSlave" type="checkbox" v-checked="master">
	 </doc:source>
	 <doc:scenario>
	 it('should check both checkBoxes', function() {
	 expect(element('.doc-example-live #checkSlave').prop('checked')).toBeFalsy();
	 input('master').check();
	 expect(element('.doc-example-live #checkSlave').prop('checked')).toBeTruthy();
	 });
	 </doc:scenario>
	 </doc:example>
	 *
	 * @element INPUT
	 * @param {expression} vChecked VX expression that will be evaluated.
	 */

	/**
	 * @vxdoc directive
	 * @name vx.directive:vMultiple
	 * @restrict A
	 *
	 * @description
	 * The HTML specs do not require browsers to preserve the special attributes such as multiple.
	 * (The presence of them means true and absence means false)
	 * This prevents the vx compiler from correctly retrieving the binding expression.
	 * To solve this problem, we introduce the `vMultiple` directive.
	 *
	 * @example
	 <doc:example>
	 <doc:source>
	 Check me check multiple: <input type="checkbox" v-model="checked"><br/>
	 <select id="select" v-multiple="checked">
	 <option>Misko</option>
	 <option>Igor</option>
	 <option>Vojta</option>
	 <option>Di</option>
	 </select>
	 </doc:source>
	 <doc:scenario>
	 it('should toggle multiple', function() {
	 expect(element('.doc-example-live #select').prop('multiple')).toBeFalsy();
	 input('checked').check();
	 expect(element('.doc-example-live #select').prop('multiple')).toBeTruthy();
	 });
	 </doc:scenario>
	 </doc:example>
	 *
	 * @element SELECT
	 * @param {expression} vMultiple VX expression that will be evaluated.
	 */

	/**
	 * @vxdoc directive
	 * @name vx.directive:vReadonly
	 * @restrict A
	 *
	 * @description
	 * The HTML specs do not require browsers to preserve the special attributes such as readonly.
	 * (The presence of them means true and absence means false)
	 * This prevents the vx compiler from correctly retrieving the binding expression.
	 * To solve this problem, we introduce the `vReadonly` directive.
	 * @example
	 <doc:example>
	 <doc:source>
	 Check me to make text readonly: <input type="checkbox" v-model="checked"><br/>
	 <input type="text" v-readonly="checked" value="I'm VX"/>
	 </doc:source>
	 <doc:scenario>
	 it('should toggle readonly attr', function() {
	 expect(element('.doc-example-live :text').prop('readonly')).toBeFalsy();
	 input('checked').check();
	 expect(element('.doc-example-live :text').prop('readonly')).toBeTruthy();
	 });
	 </doc:scenario>
	 </doc:example>
	 *
	 * @element INPUT
	 * @param {string} expression VX expression that will be evaluated.
	 */

	/**
	 * @vxdoc directive
	 * @name vx.directive:vSelected
	 * @restrict A
	 *
	 * @description
	 * The HTML specs do not require browsers to preserve the special attributes such as selected.
	 * (The presence of them means true and absence means false)
	 * This prevents the vx compiler from correctly retrieving the binding expression.
	 * To solve this problem, we introduced the `vSelected` directive.
	 * @example
	 <doc:example>
	 <doc:source>
	 Check me to select: <input type="checkbox" v-model="selected"><br/>
	 <select>
	 <option>Hello!</option>
	 <option id="greet" v-selected="selected">Greetings!</option>
	 </select>
	 </doc:source>
	 <doc:scenario>
	 it('should select Greetings!', function() {
	 expect(element('.doc-example-live #greet').prop('selected')).toBeFalsy();
	 input('selected').check();
	 expect(element('.doc-example-live #greet').prop('selected')).toBeTruthy();
	 });
	 </doc:scenario>
	 </doc:example>
	 *
	 * @element OPTION
	 * @param {string} expression VX expression that will be evaluated.
	 */

	/**
	 * @vxdoc directive
	 * @name v.directive:vOpen
	 * @restrict A
	 *
	 * @description
	 * The HTML specs do not require browsers to preserve the special attributes such as open.
	 * (The presence of them means true and absence means false)
	 * This prevents the vx compiler from correctly retrieving the binding expression.
	 * To solve this problem, we introduce the `vOpen` directive.
	 *
	 * @example
	 <doc:example>
	 <doc:source>
	 Check me check multiple: <input type="checkbox" v-model="open"><br/>
	 <details id="details" v-open="open">
	 <summary>Show/Hide me</summary>
	 </details>
	 </doc:source>
	 <doc:scenario>
	 it('should toggle open', function() {
	 expect(element('#details').prop('open')).toBeFalsy();
	 input('open').check();
	 expect(element('#details').prop('open')).toBeTruthy();
	 });
	 </doc:scenario>
	 </doc:example>
	 *
	 * @element DETAILS
	 * @param {string} expression VX expression that will be evaluated.
	 */
	var vAttributeAliasDirectives = {};

	// boolean attrs are evaluated
	forEach(BOOLEAN_ATTR, function(propName, attrName) {
		var normalized = directiveNormalize('v-' + attrName);
		vAttributeAliasDirectives[normalized] = function() {
			return {
				priority : 100,
				link : function(scope, element, attr) {
					scope.$watch(attr[normalized], function vBooleanAttrWatchAction(value) {
						attr.$set(attrName, !!value);
					});
				}
			};
		};
	});

	/**
	 * @vxdoc directive
	 * @name vx.directive:vHref
	 * @restrict A
	 *
	 * @description
	 * Using VX markup like {{hash}} in an href attribute makes
	 * the page open to a wrong URL, if the user clicks that link before
	 * vx has a chance to replace the {{hash}} with actual URL, the
	 * link will be broken and will most likely return a 404 error.
	 * The `vHref` directive solves this problem.
	 *
	 * The buggy way to write it:
	 * <pre>
	 * <a href="http://www.gravatar.com/avatar/{{hash}}"/>
	 * </pre>
	 *
	 * The correct way to write it:
	 * <pre>
	 * <a v-href="http://www.gravatar.com/avatar/{{hash}}"/>
	 * </pre>
	 *
	 * @element A
	 * @param {template} vHref any string which can contain `{{}}` markup.
	 *
	 * @example
	 * This example uses `link` variable inside `href` attribute:
	 <doc:example>
	 <doc:source>
	 <input v-model="value" /><br />
	 <a id="link-1" href v-click="value = 1">link 1</a> (link, don't reload)<br />
	 <a id="link-2" href="" v-click="value = 2">link 2</a> (link, don't reload)<br />
	 <a id="link-3" v-href="/{{'123'}}">link 3</a> (link, reload!)<br />
	 <a id="link-4" href="" name="xx" v-click="value = 4">anchor</a> (link, don't reload)<br />
	 <a id="link-5" name="xxx" v-click="value = 5">anchor</a> (no link)<br />
	 <a id="link-6" v-href="{{value}}">link</a> (link, change location)
	 </doc:source>
	 <doc:scenario>
	 it('should execute v-click but not reload when href without value', function() {
	 element('#link-1').click();
	 expect(input('value').val()).toEqual('1');
	 expect(element('#link-1').attr('href')).toBe("");
	 });

	 it('should execute v-click but not reload when href empty string', function() {
	 element('#link-2').click();
	 expect(input('value').val()).toEqual('2');
	 expect(element('#link-2').attr('href')).toBe("");
	 });

	 it('should execute v-click and change url when v-href specified', function() {
	 expect(element('#link-3').attr('href')).toBe("/123");

	 element('#link-3').click();
	 expect(browser().window().path()).toEqual('/123');
	 });

	 it('should execute v-click but not reload when href empty string and name specified', function() {
	 element('#link-4').click();
	 expect(input('value').val()).toEqual('4');
	 expect(element('#link-4').attr('href')).toBe('');
	 });

	 it('should execute v-click but not reload when no href but name specified', function() {
	 element('#link-5').click();
	 expect(input('value').val()).toEqual('5');
	 expect(element('#link-5').attr('href')).toBe(undefined);
	 });

	 it('should only change url when only v-href', function() {
	 input('value').enter('6');
	 expect(element('#link-6').attr('href')).toBe('6');

	 element('#link-6').click();
	 expect(browser().location().url()).toEqual('/6');
	 });
	 </doc:scenario>
	 </doc:example>
	 */

	/**
	 * @vxdoc directive
	 * @name vx.directive:vSrc
	 * @restrict A
	 *
	 * @description
	 * Using VX markup like `{{hash}}` in a `src` attribute doesn't
	 * work right: The browser will fetch from the URL with the literal
	 * text `{{hash}}` until VX replaces the expression inside
	 * `{{hash}}`. The `vSrc` directive solves this problem.
	 *
	 * The buggy way to write it:
	 * <pre>
	 * <img src="http://www.gravatar.com/avatar/{{hash}}"/>
	 * </pre>
	 *
	 * The correct way to write it:
	 * <pre>
	 * <img v-src="http://www.gravatar.com/avatar/{{hash}}"/>
	 * </pre>
	 *
	 * @element IMG
	 * @param {template} vSrc any string which can contain `{{}}` markup.
	 */
	/**
	 * @vxdoc directive
	 * @name vx.directive:vSrcset
	 * @restrict A
	 *
	 * @description
	 * Using vx markup like `{{hash}}` in a `srcset` attribute doesn't
	 * work right: The browser will fetch from the URL with the literal
	 * text `{{hash}}` until vx replaces the expression inside
	 * `{{hash}}`. The `vSrcset` directive solves this problem.
	 *
	 * The buggy way to write it:
	 * <pre>
	 * <img srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/>
	 * </pre>
	 *
	 * The correct way to write it:
	 * <pre>
	 * <img v-srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/>
	 * </pre>
	 *
	 * @element IMG
	 * @param {template} vSrcset any string which can contain `{{}}` markup.
	 */
	// v-src, v-srcset, v-href are interpolated
	forEach(['src', 'srcset', 'href'], function(attrName) {
		var normalized = directiveNormalize('v-' + attrName);
		vAttributeAliasDirectives[normalized] = function() {
			return {
				priority : 99, // it needs to run after the attributes are interpolated
				link : function(scope, element, attr) {
					attr.$observe(normalized, function(value) {
						if (!value)
							return;
						attr.$set(attrName, value);

						// on IE, if "v:src" directive declaration is used and "src" attribute doesn't exist
						// then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
						// to set the property as well to achieve the desired effect.
						// we use attr[attrName] value since $set can sanitize the url.
						if (msie)
							element.prop(attrName, attr[attrName]);
					});
				}
			};
		};
	});

	/**
	 * @vxdoc directive
	 * @name vx.directive:vTransclude
	 *
	 * @description
	 * Insert the transcluded DOM here.
	 *
	 * @element ANY
	 *
	 * @example
	 <doc:example module="transclude">
	 <doc:source>
	 <script>
	 function Ctrl($scope) {
	 $scope.title = 'Lorem Ipsum';
	 $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
	 }

	 vx.module('transclude', [])
	 .directive('pane', function(){
	 return {
	 restrict: 'E',
	 transclude: true,
	 scope: 'isolate',
	 locals: { title:'bind' },
	 template: '<div style="border: 1px solid black;">' +
	 '<div style="background-color: gray">{{title}}</div>' +
	 '<div v-transclude></div>' +
	 '</div>'
	 };
	 });
	 </script>
	 <div v-controller="Ctrl">
	 <input v-model="title"><br>
	 <textarea v-model="text"></textarea> <br/>
	 <pane title="{{title}}">{{text}}</pane>
	 </div>
	 </doc:source>
	 <doc:scenario>
	 it('should have transcluded', function() {
	 input('title').enter('TITLE');
	 input('text').enter('TEXT');
	 expect(binding('title')).toEqual('TITLE');
	 expect(binding('text')).toEqual('TEXT');
	 });
	 </doc:scenario>
	 </doc:example>
	 *
	 */
	/*
	function vTranscludeDirective() {
		return {
			restrict : 'AC',
			controller : ['$transclude', '$element',
			function($transclude, $element) {
				$transclude(function(clone) {
					$element.append(clone);
				});
			}]

		};
	}
	*/
	/*
	function styleDirective() {
		return {
			restrict : 'E',
			terminal : true
		};
	}
	*/

	/**
	 * @vxdoc directive
	 * @name vx.directive:vInclude
	 * @restrict ECA
	 *
	 * @description
	 * Fetches, compiles and includes an external HTML fragment.
	 *
	 * Keep in mind that Same Origin Policy applies to included resources
	 * (e.g. vInclude won't work for cross-domain requests on all browsers and for
	 *  file:// access on some browsers).
	 *
	 * Additionally, you can also provide animations via the vAnimate attribute to animate the **enter**
	 * and **leave** effects.
	 *
	 * @animations
	 * enter - happens just after the vInclude contents change and a new DOM element is created and injected into the vInclude container
	 * leave - happens just after the vInclude contents change and just before the former contents are removed from the DOM
	 *
	 * @scope
	 *
	 * @param {string} vInclude|src vx expression evaluating to URL. If the source is a string constant,
	 *                 make sure you wrap it in quotes, e.g. `src="'myPartialTemplate.html'"`.
	 * @param {string=} onload Expression to evaluate when a new partial is loaded.
	 *
	 * @param {string=} autoscroll Whether `vInclude` should call {@link vx.$anchorScroll
	 *                  $anchorScroll} to scroll the viewport after the content is loaded.
	 *
	 *                  - If the attribute is not set, disable scrolling.
	 *                  - If the attribute is set without value, enable scrolling.
	 *                  - Otherwise enable scrolling only if the expression evaluates to truthy value.
	 *
	 * @example
	 <example animations="true">
	 <file name="index.html">
	 <div v-controller="Ctrl">
	 <select v-model="template" v-options="t.name for t in templates">
	 <option value="">(blank)</option>
	 </select>
	 url of the template: <tt>{{template.url}}</tt>
	 <hr/>
	 <div class="example-animate-container"
	 v-include="template.url"
	 v-animate="{enter: 'example-enter', leave: 'example-leave'}"></div>
	 </div>
	 </file>
	 <file name="script.js">
	 function Ctrl($scope) {
	 $scope.templates =
	 [ { name: 'template1.html', url: 'template1.html'}
	 , { name: 'template2.html', url: 'template2.html'} ];
	 $scope.template = $scope.templates[0];
	 }
	 </file>
	 <file name="template1.html">
	 <div>Content of template1.html</div>
	 </file>
	 <file name="template2.html">
	 <div>Content of template2.html</div>
	 <file name="animations.css">
	 .example-leave,
	 .example-enter {
	 -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
	 -moz-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
	 -ms-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
	 -o-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
	 transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
	 position:absolute;
	 top:0;
	 left:0;
	 right:0;
	 bottom:0;
	 }
	 .example-animate-container > * {
	 display:block;
	 padding:10px;
	 }
	 .example-enter {
	 top:-50px;
	 }
	 .example-enter.example-enter-active {
	 top:0;
	 }
	 .example-leave {
	 top:0;
	 }
	 .example-leave.example-leave-active {
	 top:50px;
	 }
	 /file>
	 <file name="scenario.js">
	 it('should load template1.html', function() {
	 expect(element('.doc-example-live [v-include]').text()).
	 toMatch(/Content of template1.html/);
	 });
	 it('should load template2.html', function() {
	 select('template').option('1');
	 expect(element('.doc-example-live [v-include]').text()).
	 toMatch(/Content of template2.html/);
	 });
	 it('should change to blank', function() {
	 select('template').option('');
	 expect(element('.doc-example-live [v-include]').text()).toEqual('');
	 });
	 </file>
	 </example>
	 */

	/**
	 * @vxdoc event
	 * @name vx.directive:vInclude#$includeContentRequested
	 * @eventOf vx.directive:vInclude
	 * @eventType emit on the scope vInclude was declared in
	 * @description
	 * Emitted every time the vInclude content is requested.
	 */

	/**
	 * @vxdoc event
	 * @name vx.directive:vInclude#$includeContentLoaded
	 * @eventOf vx.directive:vInclude
	 * @eventType emit on the current vInclude scope
	 * @description
	 * Emitted every time the vInclude content is reloaded.
	 */
	vIncludeDirective.$inject = ['$http', '$templateCache', '$compile', '$animator'];
	function vIncludeDirective($http, $templateCache, $compile, $animator) {
		return {
			restrict : 'ECA',
			terminal : true,
			compile : function(element, attr) {
				var srcExp = attr.vInclude || attr.src, onloadExp = attr.onload || '';
				return function(scope, element, attr) {
					var animate = $animator(scope, attr);
					var changeCounter = 0, childScope;
					var clearContent = function() {
						if (childScope) {
							childScope.$destroy();
							childScope = null;
						}
						//element.html('');
						animate.leave(element.contents(), element);
					};

					scope.$watch(srcExp, function vIncludeWatchAction(src) {
						var thisChangeId = ++changeCounter;
						if (src) {
							//XXX need $scope and ajaxPort???
							$http.get(src, {
								cache : $templateCache
							}).success(function(response) {
								if (thisChangeId !== changeCounter)
									return;
								if (childScope)
									childScope.$destroy();
								childScope = scope.$new();

								animate.leave(element.contents(), element);
								var contents = jqLite('<div/>').html(response).contents();
								animate.enter(contents, element);

								$compile(element.contents())(childScope);

								childScope.$emit('$includeContentLoaded');
								scope.$eval(onloadExp);
							}).error(function() {
								if (thisChangeId === changeCounter)
									clearContent();
							});
							scope.$emit('$includeContentRequested');
						} else {
							clearContent();
						}
					});
				};
			}
		};
	}

	var vViewControllers = viewControllers();

	function viewControllers() {
		var $httpBackend = null;

		function getTransition(scope, attrs, $targets, $animator) {
			var vAnimateAttr = attrs.vAnimate;
			if (vAnimateAttr) {
				var animate = $animator(scope, attrs);
				return function(newEl, oldEl, remove, back) {
					if (newEl && newEl.length) {
						if (oldEl && oldEl.length) {
							if (remove)
								animate.leave(oldEl, oldEl.parent(), null, back);
							else
								animate.hide(oldEl, oldEl.parent(), null, back);
						}
						animate.show(newEl, newEl.parent(), null, back);
					}
				};
			}
			return $targets.transition(attrs.vTransition);
		}


		vViewportController.$inject = ['$scope', '$element', '$attrs', '$targets', '$http', '$templateCache', '$compile', '$log', '$httpBackend', '$$remote', '$animator'];
		function vViewportController(scope, element, attr, $targets, $http, $templateCache, $compile, $log, httpBackend, $$remote, $animator) {
			$httpBackend = httpBackend;

			/*jshint validthis:true*/
			var view = this, pages = {
				activePage : null,
				activeIndex : 0,
				activeMax : 0,
				track : []
			}, subviews = [];
			var vpId = attr.vViewport || attr.id, transition = getTransition(scope, attr, $targets, $animator), noHistory = attr.history !== 'true', //
			onloadExp = attr.onload || '', onbeforeloadExp = attr.onbeforeload || '';

			if (!vpId)
				throw vError(100, 'viewport must have id from "v-viewport" or "id" attribute');

			var parentView = element.parent().controller('vViewport');
			var childScope = scope.$new();
			scope.$$viewport = vpId;

			view.$id = vpId;
			view.$noHistory = noHistory;
			var applied = attr.apply === 'true';
			var ajaxPort = attr.ajaxPort;

			if (applied) {
				scope.$$applied = scope;
				scope.$repaint = repaintFactory(element);
			}
			if (ajaxPort)
				scope.$$ajaxPort = ajaxPort;

			view.$activeElement = jqLite(wrapInner(element[0], element.contents()));
			$compile(view.$activeElement)(childScope);

			view.$pages = pages;
			view.$subviews = subviews;

			scope.$Remoting = scope.$Submitting = 0;
			view.$$remoteTouch = function(submit) {
				scope.$Remoting++;
				if (submit)
					scope.$Submitting++;
			};

			view.$init = function() {
				if (parentView)
					parentView.$subviews.push(this);
				if ($targets.$viewports[view.$id])
					throw vError(101, 'duplicated viewport {0}', view.$id);
				$targets.$viewports[view.$id] = view;
				var target = attr.href;
				if (target)
					$targets(view.$id, target, view.$noHistory);
			};

			view.$destroy = function() {
				if (!view.$$destroyed) {
					$targets.clearTarget(view.$id);
					if (parentView)
						arrayRemove(parentView.$subviews, view);
					view.$clearSubviews();
					view.$clearPages();
					view.$activeElement = null;
					view.$$destroyed = true;
					childScope.$destroy();
					scope.$destroy();
				}
			};

			view.$clearSubviews = function() {
				for (var i = 0; i < subviews.length; i++) {
					var v = subviews[i];
					v.$destroy();
				}
			};

			view.$clearPages = function() {
				for (var i = 0; i < pages.track.length; i++) {
					var p = pages.track[i];
					p.$destroy();
				}
				pages.activeIndex = 0;
				pages.activeMax = 0;
				pages.track = [];
				pages.activePage = null;
			};

			view.$addPage = function(page) {
				pages.track.push(page);
				page.$index = pages.track.length;
			};

			view.$removePage = function(page) {
				arrayRemove(pages.track, page);
			};

			view.$trackPage = function(id, active) {
				var page, match = id.match(/^([\+\-]?)(\d+)$/), index, back;
				if (!match)
					throw vError(102, 'invalid page track, require [+-]number: {0}', id);
				index = int(id);
				if (match[1]) {// relative
					back = index < 0;
					if (pages.activeIndex < 1 || pages.track.length < 2)
						return;
					index = (pages.activeIndex + index - 1) % pages.track.length;
					if (index < 0)
						index += pages.track.length;
					index += 1;
					if (back && index > pages.activeIndex)
						index = 1;
					if (!back && index < pages.activeIndex)
						index = pages.track.length;
				} else {
					back = index < pages.activeIndex;
					if (index > pages.track.length)
						throw vError(103, 'page over max index: {0}', pages.track.length);
				}
				if (index === pages.activeIndex)
					return;
				if (!active && index > pages.activeMax)
					throw vError(104, 'page over max index: {0}', pages.activeMax);

				if (index === 0) {
					//XXX n === 0 is special, it means reset viewport (now just activeMax reset)
					if (!view.$reload)
						return;
					$log.debug('reload viewport "' + vpId + '"');
					return view.$reload();
				} else {
					pages.activeIndex = index;
					if (active)
						pages.activeMax = match[1] ? index : Math.max(index, pages.activeMax);
				}

				if (active) {
					$log.debug('viewport forward to page#' + index + ' in "' + vpId + '"');
				} else {
					$log.debug('viewport track to page#' + index + ' in "' + vpId + '"');
				}

				page = pages.track[index - 1];
				page.$load(back);
			};

			view.$load = function(newtarget, back) {
				var src = newtarget.url;
				if (onbeforeloadExp)
					src = scope.$eval(onbeforeloadExp) || newtarget.url;
				if (src) {
					view.$rootUrl = src;
					var base = getBase(src);
					view.$reload = function(back) {
						$http.get(src, {
							cache : $templateCache,
							$scope : scope
						}).success(function(response) {
							setInnerHTML(scope, element[0], response, function(newElement) {
								var oldEl = view.$activeElement;
								var el = view.$activeElement = jqLite(newElement);

								view.$clearPages();
								view.$clearSubviews();

								if (childScope)
									childScope.$destroy();

								childScope = scope.$new();
								$compile(el)(childScope);

								transition(oldEl, el, true, back);

								childScope.$root.$broadcast('$viewportContentLoaded', vpId, src);
								scope.$eval(onloadExp, injectRemote(element, null, onloadExp, false, $$remote));

								if (pages.track.length)
									view.$trackPage('1', true);

							}, base, false);
						}).error(function(reason, code, headers, config) {
							throw vError(105, 'http error [{0}] - {1}: {2}', code, reason, config.url);
						});
					};
					view.$reload(back);
				} else {
					throw vError(106, 'target url is null');
				}
			};

		}


		vPageController.$inject = ['$scope', '$element', '$attrs', '$http', '$templateCache', '$targets', '$compile', '$browser', '$httpBackend', '$$remote', '$animator'];
		function vPageController(scope, element, attr, $http, $templateCache, $targets, $compile, $browser, httpBackend, $$remote, $animator) {
			$httpBackend = httpBackend;

			/*jshint validthis:true*/
			var page = this, viewport = element.parent().controller('vViewport');
			var transition = getTransition(scope, attr, $targets, $animator), onloadExp = attr.onload, target = attr.href;
			var forms = [];

			if (!viewport)
				throw vError(107, 'v-page must inside v-viewport');

			element[0].style.display = 'none';
			if (!target)
				page.$$loaded = 'loaded';

			page.$element = element;

			page.$destroy = function() {
				page.$element = null;
				forms = [];
				viewport.$removePage(page);
			};

			page.$addForm = function(form) {
				forms.push(form);
			};

			page.$removeForm = function(form) {
				arrayRemove(forms, form);
			};

			page.$bind = function() {
				forEach(forms, function(f) {
					f.$bind();
				});
			};

			page.$unbind = function() {
				forEach(forms, function(f) {
					f.$unbind();
				});
			};

			page.$load = function(back) {
				if (target && !page.$$loaded) {
					var base = getBase(target);
					$http.get(target, {
						cache : $templateCache,
						$scope : scope
					}).success(function(response) {
						setInnerHTML(scope, element[0], response, function() {
							page.$$loaded = 'loaded';
							loadPage(page, back);
						}, base, true);
					}).error(function(reason, code, headers, config) {
						throw vError(108, 'http error [{0}] - {1}: {2}', code, reason, config.url);
					});
				} else {
					$browser.defer(function() {
						loadPage(page, back);
						scope.$apply(null, 'v-page');
					});
				}
			};

			/*
			 function loadPage(page, back) {
			 var el = clonePageElement(element);
			 element.after(el);
			 $compile(el.contents())(scope, null, false);
			 scope.$root.$broadcast('$pageContentLoaded', viewport.$id, page.$index, target);
			 scope.$eval(onloadExp);
			 transition(viewport.$pages.activePage.$element, el, true, back);
			 viewport.$pages.activePage = page;
			 }

			 function clonePageElement(el) {
			 var clone = jqLite(el[0].cloneNode(false)), children = el[0].childNodes;
			 for (var i = 0; i < children.length; i++) {
			 if (_nodeName(children[i]) !== 'SCRIPT')
			 clone.append(children[i].cloneNode(true));
			 }
			 return clone;
			 }
			 */

			function loadPage(page, back) {
				var el = element, lastPage = viewport.$pages.activePage;
				//XXX only compile once, otherwise memory-leak due to scope not $destroy
				if (lastPage)
					lastPage.$unbind();
				if (page.$$loaded !== 'compiled') {
					$compile(el.contents())(scope, null, false);
					page.$$loaded = 'compiled';
				} else {
					page.$bind();
				}

				scope.$root.$broadcast('$pageContentLoaded', viewport.$id, page.$index, target);
				scope.$eval(onloadExp, injectRemote(el, null, onloadExp, false, $$remote));
				transition(lastPage && lastPage.$element, el, false, back);
				viewport.$pages.activePage = page;
			}

		}

		return {
			viewport : vViewportController,
			page : vPageController
		};

		// -------------------- inner function ----------------------------
		function wrapInner(parent, children) {
			var div = document.createElement('div');
			div.className = 'viewport-wrapper';
			parent.appendChild(div);
			if (children) {
				for (var i = 0, ii = children.length; i < ii; i++) {
					div.appendChild(children[i]);
				}
			}
			return div;
		}

		// append HTML (include script)
		function setInnerHTML(scope, el, htmlCode, done, root, isPage) {
			el = isPage ? el : wrapInner(el);
			el.style.display = 'none';
			parseElements(htmlCode, el, scope, done, root);
		}

		function getBase(path) {
			var p = path && path.lastIndexOf('/');
			if (!p)
				return "";
			return path.substring(0, p + 1);
		}

		function getPath(src, root) {
			if (src.charAt(0) === '/')
				return src;
			return root + src;
		}

		function createElements(htmlCode) {
			//*** jimmy, for IE innerHTML will load script by src, so replace 'src=' to 'v-src='
			htmlCode = htmlCode.replace(/<script([^>]*)(src\s*=)([^>]*)>/gi, "<script$1v-src=$3>");
			var div = document.createElement('div');
			if (msie) {
				htmlCode = '<div style="display:none">for IE</div>' + htmlCode;
				div.innerHTML = htmlCode;
				div.removeChild(div.firstChild);
			} else {
				div.innerHTML = htmlCode;
			}
			var array = [], fc = div.firstChild;
			while (fc) {
				div.removeChild(fc);
				array.push(fc);
				fc = div.firstChild;
			}
			if (msie)
				IE_GC(div);
			return array;
		}

		function parseElements(htmlCode, el, scope, done, root) {
			var port = scope.$$ajaxPort;
			var nodes = createElements(htmlCode), node, remoteCount = 0, remoteSize = 0, i, ii;
			for ( i = 0, ii = nodes.length; i < ii; i++) {
				node = nodes[i];
				if (node.nodeName === 'SCRIPT' && node.getAttribute('v-src'))
					remoteSize++;
			}
			for ( i = 0; i < nodes.length; i++) {
				node = nodes[i];
				if (node.nodeName === 'SCRIPT') {
					if (node.getAttribute('v-src'))
						remote(node);
					else
						local(node);
					if (msie)
						IE_GC(node);
				} else {
					el.appendChild(node);
				}
			}

			if (remoteSize === 0 && done)
				done(el);

			function local(node) {
				var script = document.createElement('script');
				script.type = node.type || 'text/javascript';
				// for template
				if (node.id)
					script.id = node.id;
				// for IE cannot use 'innerHTML', just use 'text'
				script.text = node.text;
				el.appendChild(script);
			}

			// for script signature is httpBackend(node, url, type, callback, ajaxPort)
			function remote(node) {
				var url = getPath(node.getAttribute('v-src'), root), type = node.type || 'text/javascript';
				var doneWrapper = function(status, response, headers) {
					remoteCount++;
					if (done && remoteCount === remoteSize)
						scope.$apply(function() {
							done(el);
						}, 'script->' + url);
				};
				$httpBackend(el, url, type, doneWrapper, port);
			}

		}

	}

	// add form nested viewport process
	vViewportDirective.$inject = ['$targets'];
	function vViewportDirective($targets) {
		return {
			restrict : 'EA',
			scope : true,
			terminal : true,
			priority : 99,
			controller : vViewControllers.viewport,
			link : function(scope, element, attr, ctrl) {
				ctrl.$init();
				element.bind('$destroy', function() {
					ctrl.$destroy();
					cleanupClosure(ctrl);
				});
			}
		};
	}

	function vPageDirective() {
		return {
			restrict : 'EA',
			terminal : true, // disable page inner compile for lazy-compile
			require : ['vPage', '^vViewport'],
			priority : 99,
			controller : vViewControllers.page,
			link : function(scope, element, attr, ctrl) {
				ctrl[1].$addPage(ctrl[0]);
				element.bind('$destroy', function() {
					ctrl[0].$destroy();
					cleanupClosure(ctrl[0]);
				});
			}
		};
	}

	function vViewSetupDirective() {
		return {
			require : '^vViewport',
			controller : '@@'
		};
	}


	/*
	vTargetDirective.$inject = ['$targets', '$interpolate'];
	function vTargetDirective($targets, $interpolate) {
		return {
			restrict : 'A',
			link : function(scope, element, attr) {
				var target = attr.vTarget || attr.target || element.controller('vViewport'), href = element.attr('href');

				if (href) {
					var hrefFn = $interpolate(href);
					element.bind('click', function(event) {
						//scope.$apply(function() {
						var h = hrefFn(scope);
						$targets(target, h);
						//}, 'v-target');
						event.preventDefault();
						//event.stopPropagation();
					});
				}
			}
		};
	}
	*/

	/*
	vTrackDirective.$inject = ['$targets'];
	function vTrackDirective($targets) {
		return {
			restrict : 'A',
			link : function(scope, element, attr) {
				if (attr.vTrack) {
					var steps = attr.vTrack, readonly = isDefined(attr.readonly), //
					flag = steps.match(/^(#?)([\+\-]?)(\d+)$/), viewportCtrl = element.controller('vViewport');
					if (!flag)
						throw vError(109, 'invalid track format, require [#][+-]number: {0}', steps);
					var page = flag[1], relative = flag[2];
					if (page) {
						if (!viewportCtrl)
							throw vError(110, 'no parent viewport found for track prefix with "#"');
						steps = steps.substring(1);
					}
					var n = int(steps), disabled = false;
					if (relative) {
						steps = n > 0 ? '+1' : '-1';
					}

					if (!readonly) {
						element.bind('click', function(event) {
							//scope.$apply(function(){
							if (!disabled) {
								if (!page)
									$targets.track(steps);
								else
									viewportCtrl.$trackPage(steps, false);
							}
							//}, 'v-track');
							event.preventDefault();
							//event.stopPropagation();
						});
					}

					if (!page) {
						if (relative) {
							scope.$watch(function() {
								var t = $targets.track.info;
								return t.tracks.length + ':' + t.index;
							}, function(status) {
								var info = $targets.track.info;
								if (info.tracks.length < 2 || (relative === '-' && info.index === 1) || (relative === '+' && info.index === info.tracks.length)) {
									disable();
								} else {
									enable();
								}
							});
						}
					} else {
						scope.$watch(function() {
							var t = viewportCtrl.$pages;
							return t.activeMax + ':' + t.activeIndex;
						}, function(status) {
							var info = viewportCtrl.$pages;
							if (relative) {
								if (info.activeMax < 2 || (relative === '-' && info.activeIndex === 1) || (relative === '+' && info.activeIndex === info.activeMax)) {
									disable();
								} else {
									enable();
								}
							} else {
								if (n > viewportCtrl.$pages.activeMax) {
									disable();
								} else {
									enable();
								}
							}
						});
					}
				}

				function enable() {
					disabled = false;
					element.removeAttr('disabled');
					element.removeClass('v-disabled');
				}

				function disable() {
					disabled = true;
					element.attr('disabled', 'disabled');
					element.addClass('v-disabled');
				}

			}
		};
	}
	*/

	/**
	 * @vxdoc directive
	 * @name v.directive:vIf
	 * @restrict A
	 *
	 * @description
	 * The `vIf` directive removes and recreates a portion of the DOM tree (HTML)
	 * conditionally based on **"falsy"** and **"truthy"** values, respectively, evaluated within
	 * an {expression}. In other words, if the expression assigned to **vIf evaluates to a false
	 * value** then **the element is removed from the DOM** and **if true** then **a clone of the
	 * element is reinserted into the DOM**.
	 *
	 * `vIf` differs from `vShow` and `vHide` in that `vIf` completely removes and recreates the
	 * element in the DOM rather than changing its visibility via the `display` css property.  A common
	 * case when this difference is significant is when using css selectors that rely on an element's
	 * position within the DOM (HTML), such as the `:first-child` or `:last-child` pseudo-classes.
	 *
	 * Note that **when an element is removed using vIf its scope is destroyed** and **a new scope
	 * is created when the element is restored**.  The scope created within `vIf` inherits from
	 * its parent scope using prototypal inheritance.
	 * An important implication of this is if `vModel` is used within `vIf` to bind to
	 * a javascript primitive defined in the parent scope. In this case any modifications made to the
	 * variable within the child scope will override (hide) the value in the parent scope.
	 *
	 * Also, `vIf` recreates elements using their compiled state. An example scenario of this behavior
	 * is if an element's class attribute is directly modified after it's compiled, using something like
	 * jQuery's `.addClass()` method, and the element is later removed. When `vIf` recreates the element
	 * the added class will be lost because the original compiled state is used to regenerate the element.
	 *
	 * Additionally, you can provide animations via the vAnimate attribute to animate the **enter**
	 * and **leave** effects.
	 *
	 * @animations
	 * enter - happens just after the vIf contents change and a new DOM element is created and injected into the vIf container
	 * leave - happens just before the vIf contents are removed from the DOM
	 *
	 * @element ANY
	 * @scope
	 * @param {expression} vIf If the {@link guide/expression expression} is falsy then
	 *     the element is removed from the DOM tree (HTML).
	 *
	 * @example
	 <example animations="true">
	 <file name="index.html">
	 Click me: <input type="checkbox" v-model="checked" v-init="checked=true" /><br/>
	 Show when checked:
	 <span v-if="checked" v-animate="'example'">
	 I'm removed when the checkbox is unchecked.
	 </span>
	 </file>
	 <file name="animations.css">
	 .example-leave, .example-enter {
	 -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
	 -moz-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
	 -ms-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
	 -o-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
	 transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
	 }

	 .example-enter {
	 opacity:0;
	 }
	 .example-enter.example-enter-active {
	 opacity:1;
	 }

	 .example-leave {
	 opacity:1;
	 }
	 .example-leave.example-leave-active {
	 opacity:0;
	 }
	 </file>
	 </example>
	 */
	vIfDirective.$inject = ['$animator'];
	function vIfDirective($animator) {
		return {
			transclude : 'element',
			priority : 1000,
			terminal : true,
			restrict : 'A',
			compile : function(element, attr, transclude) {
				return function($scope, $element, $attr) {
					var animate = $animator($scope, $attr);
					var childElement, childScope;
					$scope.$watch($attr.vIf, function vIfWatchAction(value) {
						if (childElement) {
							animate.leave(childElement);
							childElement = undefined;
						}
						if (childScope) {
							childScope.$destroy();
							childScope = undefined;
						}
						if (toBoolean(value)) {
							childScope = $scope.$new();
							transclude(childScope, function(clone) {
								childElement = clone;
								animate.enter(clone, $element.parent(), $element);
							});
						}
					});
				};
			}
		};
	}

	/**
	 * @vxdoc directive
	 * @name vx.directive:vSwitch
	 * @restrict EA
	 *
	 * @description
	 * The vSwitch directive is used to conditionally swap DOM structure on your template based on a scope expression.
	 * Elements within vSwitch but without vSwitchWhen or vSwitchDefault directives will be preserved at the location
	 * as specified in the template.
	 *
	 * The directive itself works similar to vInclude, however, instead of downloading template code (or loading it
	 * from the template cache), vSwitch simply choses one of the nested elements and makes it visible based on which element
	 * matches the value obtained from the evaluated expression. In other words, you define a container element
	 * (where you place the directive), place an expression on the **on="..." attribute**
	 * (or the **v-switch="..." attribute**), define any inner elements inside of the directive and place
	 * a when attribute per element. The when attribute is used to inform vSwitch which element to display when the on
	 * expression is evaluated. If a matching expression is not found via a when attribute then an element with the default
	 * attribute is displayed.
	 *
	 * Additionally, you can also provide animations via the vAnimate attribute to animate the **enter**
	 * and **leave** effects.
	 *
	 * @animations
	 * enter - happens after the vSwtich contents change and the matched child element is placed inside the container
	 * leave - happens just after the vSwitch contents change and just before the former contents are removed from the DOM
	 *
	 * @usage
	 * <ANY v-switch="expression">
	 *   <ANY v-switch-when="matchValue1">...</ANY>
	 *   <ANY v-switch-when="matchValue2">...</ANY>
	 *   <ANY v-switch-default>...</ANY>
	 * </ANY>
	 *
	 * @scope
	 * @param {*} vSwitch|on expression to match against <tt>v-switch-when</tt>.
	 * @paramDescription
	 * On child elements add:
	 *
	 * * `vSwitchWhen`: the case statement to match against. If match then this
	 *   case will be displayed. If the same match appears multiple times, all the
	 *   elements will be displayed.
	 * * `vSwitchDefault`: the default case when no other case match. If there
	 *   are multiple default cases, all of them will be displayed when no other
	 *   case match.
	 *
	 * @example
	 <example animations="true">
	 <file name="index.html">
	 <div v-controller="Ctrl">
	 <select v-model="selection" v-options="item for item in items">
	 </select>
	 <tt>selection={{selection}}</tt>
	 <hr/>
	 <div
	 class="example-animate-container"
	 v-switch on="selection"
	 v-animate="{enter: 'example-enter', leave: 'example-leave'}">
	 <div v-switch-when="settings">Settings Div</div>
	 <div v-switch-when="home">Home Span</div>
	 <div v-switch-default>default</div>
	 </div>
	 </div>
	 </file>
	 <file name="script.js">
	 function Ctrl($scope) {
	 $scope.items = ['settings', 'home', 'other'];
	 $scope.selection = $scope.items[0];
	 }
	 </file>
	 <file name="animations.css">
	 .example-leave, .example-enter {
	 -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
	 -moz-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
	 -ms-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
	 -o-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
	 transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;

	 position:absolute;
	 top:0;
	 left:0;
	 right:0;
	 bottom:0;
	 }

	 .example-animate-container > * {
	 display:block;
	 padding:10px;
	 }

	 .example-enter {
	 top:-50px;
	 }
	 .example-enter-active.example-enter-active {
	 top:0;
	 }

	 .example-leave {
	 top:0;
	 }
	 .example-leave-active.example-leave-active {
	 top:50px;
	 }
	 </file>
	 <file name="scenario.js">
	 it('should start in settings', function() {
	 expect(element('.doc-example-live [v-switch]').text()).toMatch(/Settings Div/);
	 });
	 it('should change to home', function() {
	 select('selection').option('home');
	 expect(element('.doc-example-live [v-switch]').text()).toMatch(/Home Span/);
	 });
	 it('should select default', function() {
	 select('selection').option('other');
	 expect(element('.doc-example-live [v-switch]').text()).toMatch(/default/);
	 });
	 </file>
	 </example>
	 */
	/*
	vSwitchDirective.$inject = ['$animator'];
	function vSwitchDirective($animator) {
		return {
			restrict : 'EA',
			require : 'vSwitch',
			// asks for $scope to fool the BC controller module
			controller : ['$scope',
			function vSwitchController() {
				this.cases = {};
			}],
			link : function(scope, element, attr, vSwitchController) {
				var animate = $animator(scope, attr);
				var watchExpr = attr.vSwitch || attr.on, selectedTranscludes, selectedElements, selectedScopes = [];

				scope.$watch(watchExpr, function vSwitchWatchAction(value) {
					for (var i = 0, ii = selectedScopes.length; i < ii; i++) {
						selectedScopes[i].$destroy();
						animate.leave(selectedElements[i]);
					}
					selectedElements = [];
					selectedScopes = [];

					if (( selectedTranscludes = vSwitchController.cases['!' + value] || vSwitchController.cases['?'])) {
						scope.$eval(attr.change);
						forEach(selectedTranscludes, function(selectedTransclude) {
							var selectedScope = scope.$new();
							selectedScopes.push(selectedScope);
							selectedTransclude.transclude(selectedScope, function(caseElement) {
								var anchor = selectedTransclude.element;
								selectedElements.push(caseElement);
								animate.enter(caseElement, anchor.parent(), anchor);
							});
						});
					}
				});
			}
		};
	}
	*/

	function vSwitchWhenDirective() {
		return {
			restrict : 'AC',
			transclude : 'element',
			priority : 500,
			require : '^vSwitch',
			compile : function(element, attrs, transclude) {
				return function(scope, element, attr, ctrl) {
					ctrl.cases['!' + attrs.vSwitchWhen] = (ctrl.cases['!' + attrs.vSwitchWhen] || []);
					ctrl.cases['!' + attrs.vSwitchWhen].push({
						transclude : transclude,
						element : element
					});
				};
			}
		};
	}

	function vSwitchDefaultDirective() {
		return {
			restrict : 'AC',
			transclude : 'element',
			priority : 500,
			require : '^vSwitch',
			compile : function(element, attrs, transclude) {
				return function(scope, element, attr, ctrl) {
					ctrl.cases['?'] = (ctrl.cases['?'] || []);
					ctrl.cases['?'].push({
						transclude : transclude,
						element : element
					});
				};
			}
		};
	}

	/**
	 * @vxdoc directive
	 * @name vx.directive:a
	 * @restrict E
	 *
	 * @description
	 * Modifies the default behavior of html A tag, so that the default action is prevented when href
	 * attribute is empty.
	 *
	 * The reasoning for this change is to allow easy creation of action links with `vClick` directive
	 * without changing the location or causing page reloads, e.g.:
	 * `<a href="" v-click="model.$save()">Save</a>`
	 */
	function htmlAnchorDirective() {
		return {
			restrict : 'E',
			compile : function(element, attr) {
				if (msie <= 8) {
					// turn <a href v-click="..">link</a> into a stylable link in IE
					// but only if it doesn't have name attribute, in which case it's an anchor
					if (!attr.href && !attr.name) {
						attr.$set('href', '');
					}
					// add a comment node to anchors to workaround IE bug that causes element content to be reset
					// to new attribute content if attribute is updated with value containing @ and element also
					// contains value with @
					// see issue #1949
					element.append(document.createComment('IE fix'));
				}

				return function(scope, element) {
					// if we have no href url, then don't navigate anywhere.
					if (!element.attr('href')) {
						element.bind('click', function(event) {
							event.preventDefault();
							//event.stopPropagation();
							//return false;
							// Needed for opera
						});
					}
				};
			}
		};
	}

	/**
	 * @vxdoc directive
	 * @name vx.directive:vRepeat
	 *
	 * @description
	 * The `vRepeat` directive instantiates a template once per item from a collection. Each template
	 * instance gets its own scope, where the given loop variable is set to the current collection item,
	 * and `$index` is set to the item index or key.
	 *
	 * Special properties are exposed on the local scope of each template instance, including:
	 *
	 * | Variable  | Type            | Details                                                                     |
	 * |===========|=================|=============================================================================|
	 * | `$index`  | {@type number}  | iterator offset of the repeated element (0..length-1)                       |
	 * | `$first`  | {@type boolean} | true if the repeated element is first in the iterator.                      |
	 * | `$middle` | {@type boolean} | true if the repeated element is between the first and last in the iterator. |
	 * | `$last`   | {@type boolean} | true if the repeated element is last in the iterator.                       |
	 *
	 * Additionally, you can also provide animations via the vAnimate attribute to animate the **enter**,
	 * **leave** and **move** effects.
	 *
	 * @animations
	 * enter - when a new item is added to the list or when an item is revealed after a filter
	 * leave - when an item is removed from the list or when an item is filtered out
	 * move - when an adjacent item is filtered out causing a reorder or when the item contents are reordered
	 *
	 * @element ANY
	 * @scope
	 * @priority 1000
	 * @param {repeat_expression} vRepeat The expression indicating how to enumerate a collection. These
	 *   formats are currently supported:
	 *
	 *   * `variable in expression` – where variable is the user defined loop variable and `expression`
	 *     is a scope expression giving the collection to enumerate.
	 *
	 *     For example: `track in cd.tracks`.
	 *
	 *   * `(key, value) in expression` – where `key` and `value` can be any user defined identifiers,
	 *     and `expression` is the scope expression giving the collection to enumerate.
	 *
	 *     For example: `(name, age) in {'adam':10, 'amalie':12}`.
	 *
	 *   * `variable in expression track by tracking_expression` – You can also provide an optional tracking function
	 *     which can be used to associate the objects in the collection with the DOM elements. If no tractking function
	 *     is specified the v-repeat associates elements by identity in the collection. It is an error to have
	 *     more then one tractking function to  resolve to the same key. (This would mean that two distinct objects are
	 *     mapped to the same DOM element, which is not possible.)
	 *
	 *     For example: `item in items` is equivalent to `item in items track by $id(item)'. This implies that the DOM elements
	 *     will be associated by item identity in the array.
	 *
	 *     For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
	 *     `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
	 *     with the corresponding item in the array by identity. Moving the same object in array would move the DOM
	 *     element in the same way ian the DOM.
	 *
	 *     For example: `item in items track by item.id` Is a typical pattern when the items come from the database. In this
	 *     case the object identity does not matter. Two objects are considered equivalent as long as their `id`
	 *     property is same.
	 *
	 * @example
	 * This example initializes the scope to a list of names and
	 * then uses `vRepeat` to display every person:
	 <example animations="true">
	 <file name="index.html">
	 <div v-init="friends = [
	 {name:'John', age:25, gender:'boy'},
	 {name:'Jessie', age:30, gender:'girl'},
	 {name:'Johanna', age:28, gender:'girl'},
	 {name:'Joy', age:15, gender:'girl'},
	 {name:'Mary', age:28, gender:'girl'},
	 {name:'Peter', age:95, gender:'boy'},
	 {name:'Sebastian', age:50, gender:'boy'},
	 {name:'Erika', age:27, gender:'girl'},
	 {name:'Patrick', age:40, gender:'boy'},
	 {name:'Samantha', age:60, gender:'girl'}
	 ]">
	 I have {{friends.length}} friends. They are:
	 <input type="search" v-model="q" placeholder="filter friends..." />
	 <ul>
	 <li v-repeat="friend in friends | filter:q"
	 v-animate="{enter: 'example-repeat-enter',
	 leave: 'example-repeat-leave',
	 move: 'example-repeat-move'}">
	 [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
	 </li>
	 </ul>
	 </div>
	 </file>
	 <file name="animations.css">
	 .example-repeat-enter,
	 .example-repeat-leave,
	 .example-repeat-move {
	 -webkit-transition:all linear 0.5s;
	 -moz-transition:all linear 0.5s;
	 -ms-transition:all linear 0.5s;
	 -o-transition:all linear 0.5s;
	 transition:all linear 0.5s;
	 }

	 .example-repeat-enter {
	 line-height:0;
	 opacity:0;
	 }
	 .example-repeat-enter.example-repeat-enter-active {
	 line-height:20px;
	 opacity:1;
	 }

	 .example-repeat-leave {
	 opacity:1;
	 line-height:20px;
	 }
	 .example-repeat-leave.example-repeat-leave-active {
	 opacity:0;
	 line-height:0;
	 }

	 .example-repeat-move { }
	 .example-repeat-move.example-repeat-move-active { }
	 </file>
	 <file name="scenario.js">
	 it('should render initial data set', function() {
	 var r = using('.doc-example-live').repeater('ul li');
	 expect(r.count()).toBe(10);
	 expect(r.row(0)).toEqual(["1","John","25"]);
	 expect(r.row(1)).toEqual(["2","Jessie","30"]);
	 expect(r.row(9)).toEqual(["10","Samantha","60"]);
	 expect(binding('friends.length')).toBe("10");
	 });

	 it('should update repeater when filter predicate changes', function() {
	 var r = using('.doc-example-live').repeater('ul li');
	 expect(r.count()).toBe(10);

	 input('q').enter('ma');

	 expect(r.count()).toBe(2);
	 expect(r.row(0)).toEqual(["1","Mary","28"]);
	 expect(r.row(1)).toEqual(["2","Samantha","60"]);
	 });
	 </file>
	 </example>
	 */
	vRepeatDirective.$inject = ['$parse', '$animator'];
	function vRepeatDirective($parse, $animator) {
		var V_REMOVED = '$$V_REMOVED';
		return {
			transclude : 'element',
			priority : 1000,
			terminal : true,
			compile : function(element, attr, linker) {
				return function($scope, $element, $attr) {
					var animate = $animator($scope, $attr);
					var expression = $attr.vRepeat;
					var match = expression.match(/^\s*(.+)\s+in\s+(.*?)\s*(\s+track\s+by\s+(.+)\s*)?$/), trackByExp, trackByExpGetter, trackByIdFn, lhs, rhs, //
					valueIdentifier, keyIdentifier, hashFnLocals = {
						$id : hashKey
					};

					if (!match) {
						throw vError(111, "vRepeat error! Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.", expression);
					}

					lhs = match[1];
					rhs = match[2];
					trackByExp = match[4];

					if (trackByExp) {
						trackByExpGetter = $parse(trackByExp);
						trackByIdFn = function(key, value, index) {
							// assign key, value, and $index to the locals so that they can be used in hash functions
							if (keyIdentifier)
								hashFnLocals[keyIdentifier] = key;
							hashFnLocals[valueIdentifier] = value;
							hashFnLocals.$index = index;
							return trackByExpGetter($scope, hashFnLocals);
						};
					} else {
						trackByIdFn = function(key, value) {
							return hashKey(value);
						};
					}

					match = lhs.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);
					if (!match) {
						throw vError(112, "vRepeat error! '_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.", lhs);
					}
					valueIdentifier = match[3] || match[1];
					keyIdentifier = match[2];

					// Store a list of elements from previous run. This is a hash where key is the item from the
					// iterator, and the value is objects with following properties.
					//   - scope: bound scope
					//   - element: previous element.
					//   - index: position
					var lastBlockMap = {};

					//watch props
					$scope.$watchCollection(rhs, function vRepeatAction(collection) {
						var index, length, cursor = $element, // current position of the node
						nextCursor,
						// Same as lastBlockMap but it has the current state. It will become the
						// lastBlockMap on the next iteration.
						nextBlockMap = {}, arrayLength, childScope, key, value, // key/value of iteration
						trackById, collectionKeys, block, // last object information {scope, element, id}
						nextBlockOrder = [];

						if (isArrayLike(collection)) {
							collectionKeys = collection;
						} else {
							// if object, extract keys, sort them and use to determine order of iteration over obj props
							collectionKeys = [];
							for (key in collection) {
								if (collection.hasOwnProperty(key) && key.charAt(0) != '$') {
									collectionKeys.push(key);
								}
							}
							collectionKeys.sort();
						}

						arrayLength = collectionKeys.length;

						// locate existing items
						length = nextBlockOrder.length = collectionKeys.length;
						for ( index = 0; index < length; index++) {
							key = (collection === collectionKeys) ? index : collectionKeys[index];
							value = collection[key];
							trackById = trackByIdFn(key, value, index);
							if (lastBlockMap.hasOwnProperty(trackById)) {
								block = lastBlockMap[trackById];
								delete lastBlockMap[trackById];
								nextBlockMap[trackById] = block;
								nextBlockOrder[index] = block;
							} else if (nextBlockMap.hasOwnProperty(trackById)) {
								// restore lastBlockMap
								/*jshint loopfunc:true */
								forEach(nextBlockOrder, function(block) {
									if (block && block.element)
										lastBlockMap[block.id] = block;
								});
								// This is a duplicate and we need to throw an error
								throw vError(113, "vRepeat error! Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}", expression, trackById);
							} else {
								// new never before seen block
								nextBlockOrder[index] = {
									id : trackById
								};
								nextBlockMap[trackById] = false;
							}
						}

						// remove existing items
						for (key in lastBlockMap) {
							if (lastBlockMap.hasOwnProperty(key)) {
								block = lastBlockMap[key];
								animate.leave(block.element);
								forEach(block.element, function(element) {
									element[V_REMOVED] = true;
								});
								block.scope.$destroy();
							}
						}

						// we are not using forEach for perf reasons (trying to avoid #call)
						for ( index = 0, length = collectionKeys.length; index < length; index++) {
							key = (collection === collectionKeys) ? index : collectionKeys[index];
							value = collection[key];
							block = nextBlockOrder[index];

							if (block.element) {
								// if we have already seen this object, then we need to reuse the
								// associated scope/element
								childScope = block.scope;

								nextCursor = cursor[0];
								do {
									nextCursor = nextCursor.nextSibling;
								} while(nextCursor && nextCursor[V_REMOVED]);

								if (block.element[0] == nextCursor) {
									// do nothing
									cursor = block.element;
								} else {
									// existing item which got moved
									animate.move(block.element, null, cursor);
									cursor = block.element;
								}
							} else {
								// new item which we don't know about
								childScope = $scope.$new();
							}

							childScope[valueIdentifier] = value;
							if (keyIdentifier)
								childScope[keyIdentifier] = key;
							childScope.$index = index;
							childScope.$first = (index === 0);
							childScope.$last = (index === (arrayLength - 1));
							childScope.$middle = !(childScope.$first || childScope.$last);

							if (!block.element) {
								linker(childScope, function(clone) {
									animate.enter(clone, null, cursor);
									cursor = clone;
									block.scope = childScope;
									block.element = clone;
									nextBlockMap[block.id] = block;
								});
							}
						}
						lastBlockMap = nextBlockMap;
					}, true);
				};
			}
		};
	}

	/**
	 * @vxdoc directive
	 * @name vx.directive:vNonBindable
	 * @priority 1000
	 *
	 * @description
	 * Sometimes it is necessary to write code which looks like bindings but which should be left alone
	 * by vx. Use `vNonBindable` to make vx ignore a chunk of HTML.
	 *
	 * @element ANY
	 *
	 * @example
	 * In this example there are two location where a simple binding (`{{}}`) is present, but the one
	 * wrapped in `vNonBindable` is left alone.
	 *
	 * @example
	 <doc:example>
	 <doc:source>
	 <div>Normal: {{1 + 2}}</div>
	 <div v-non-bindable>Ignored: {{1 + 2}}</div>
	 </doc:source>
	 <doc:scenario>
	 it('should check v-non-bindable', function() {
	 expect(using('.doc-example-live').binding('1 + 2')).toBe('3');
	 expect(using('.doc-example-live').element('div:last').text()).
	 toMatch(/1 \+ 2/);
	 });
	 </doc:scenario>
	 </doc:example>
	 */
	/*
	function vNonBindableDirective() {
		return {
			restrict : 'AC',
			terminal : true,
			priority : 1000
		};
	}
	*/

	/**
	 * @vxdoc directive
	 * @name vx.directive:script
	 *
	 * @description
	 * Load content of a script tag, with type `text/v-template`, into `$templateCache`, so that the
	 * template can be used by `vInclude`, `vView` or directive templates.
	 *
	 * @restrict E
	 * @param {'text/v-template'} type must be set to `'text/v-template'`
	 *
	 * @example
	 <doc:example>
	 <doc:source>
	 <script type="text/v-template" id="/tpl.html">
	 Content of the template.
	 </script>

	 <a v-click="currentTpl='/tpl.html'" id="tpl-link">Load inlined template</a>
	 <div id="tpl-content" v-include src="currentTpl"></div>
	 </doc:source>
	 <doc:scenario>
	 it('should load template defined inside script tag', function() {
	 element('#tpl-link').click();
	 expect(element('#tpl-content').text()).toMatch(/Content of the template/);
	 });
	 </doc:scenario>
	 </doc:example>
	 */
	scriptDirective.$inject = ['$templateCache'];
	function scriptDirective($templateCache) {
		return {
			restrict : 'E',
			terminal : true,
			compile : function(element, attr) {
				if (attr.type == 'text/v-template') {
					var templateUrl = attr.id,
					// IE is not consistent, in scripts we have to read .text but in other nodes we have to read .textContent
					text = element[0].text;

					$templateCache.put(templateUrl, text);
				}
			}
		};
	}

	var nullFormCtrl = {
		$addControl : noop,
		$removeControl : noop,
		$setValidity : noop,
		$setDirty : noop,
		$setPristine : noop,
		$getData : noop,
		$getError : noop,
		$clearData : noop
	};

	function isValidItem(data) {
		if (data == null)
			return false;
		if (!isObject(data) || !!data.$selected)
			return true;
		return false;
	}

	var VALID_CLASS = 'v-valid', INVALID_CLASS = 'v-invalid', PRISTINE_CLASS = 'v-pristine', DIRTY_CLASS = 'v-dirty';

	/**
	 * @vxdoc object
	 * @name vx.directive:form.FormController
	 *
	 * @property {boolean} $pristine True if user has not interacted with the form yet.
	 * @property {boolean} $dirty True if user has already interacted with the form.
	 * @property {boolean} $valid True if all of the containing forms and controls are valid.
	 * @property {boolean} $invalid True if at least one containing control or form is invalid.
	 *
	 * @property {Object} $error Is an object hash, containing references to all invalid controls or
	 *  forms, where:
	 *
	 *  - keys are validation tokens (error names) — such as `required`, `url` or `email`),
	 *  - values are arrays of controls or forms that are invalid with given error.
	 *
	 * @description
	 * `FormController` keeps track of all its controls and nested forms as well as state of them,
	 * such as being valid/invalid or dirty/pristine.
	 *
	 * Each {@link vx.directive:form form} directive creates an instance
	 * of `FormController`.
	 *
	 */
	//asks for $scope to fool the BC controller module
	FormController.$inject = ['$element', '$attrs', '$parse', '$scope'];
	function FormController(element, attrs, $parse) {
		var form = this, invalidCount = 0, // used to easily determine if we are valid
		errors = form.$error = {}, controls = form.$controls = [];

		var parentForm = element.parent().controller('form') || nullFormCtrl;

		// init state
		form.$name = attrs.name || attrs.vForm;
		form.$dirty = false;
		form.$pristine = true;
		form.$valid = true;
		form.$invalid = false;

		form.$virtual = _nodeName(element) !== 'FORM';

		// Setup initial state of the control
		element.addClass(PRISTINE_CLASS);
		toggleValidCss(element, true);

		form.$submit = function() {
			element.trigger('submit');
		};

		form.$getData = (function formData() {

			function formArray(data) {
				var ret = [];
				for (var i = 0, d; i < data.length; i++) {
					if (isValidItem(data[i])) {
						d = copy(data[i]);
						ret.push(d);
					}
				}
				return ret;
			}

			function putData(data, name, value) {
				var expr = $parse(name + "=tmp");
				expr(data, {
					tmp : value
				});
			}

			return function(parent) {
				var data = {}, pdata = {};
				if (!!parent) {
					pdata = parentForm.$getData();
				}
				forEach(controls, function(model) {
					if (model.$name) {
						if (!model.$parentModel) {
							var value = model.$modelValue;
							if (isEmpty(value))
								return;
							if (model.$virtual) {
								value = formArray(value);
								if (value.length === 0)
									return;
							}
							putData(data, model.$name, value);
						}
					}
				});
				return extend({}, pdata, data);
			};

		})();

		form.$getError = function(parent) {
			var errs;
			if (parent)
				errs = extend({}, parentForm.$error, form.$error);
			else
				errs = extend({}, form.$error);
			return size(errs, true) ? errs : null;
		};
		form.$clearData = function() {
			forEach(controls, function(ctrl) {
				if (ctrl.$name) {
					if (!ctrl.$parentModel) {
						if (ctrl.$virtual) {
							for (var i = 0, d; i < ctrl.$modelValue.length; i++) {
								delete ctrl.$modelValue[i].$selected;
							}
						} else {
							ctrl.$reset();
						}
					}
				}
			});
		};

		// convenience method for easy toggling of classes
		function toggleValidCss(element, isValid, validationErrorKey) {
			validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
			element.removeClass(( isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey).addClass(( isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey);
		}


		form.$addControl = function(control, attr) {
			controls.push(control);
			// if same name, just add first one
			if (control.$name) {
				if (!form.hasOwnProperty(control.$name)) {
					form[control.$name] = control;
				}
				var watchFn = function(value) {
					var oldName = control.$name;
					if (oldName === value)
						return;
					var old = form[oldName];
					control.$name = value;
					if (old === control) {
						delete form[oldName];
						form[control.$name] = control;
					}
				};
				attr.$observe('name', watchFn);
			}
		};

		form.$removeControl = function(control) {
			if (control.$name && form[control.$name] === control) {
				delete form[control.$name];
			}
			forEach(errors, function(queue, validationToken) {
				form.$setValidity(validationToken, true, control);
			});
			arrayRemove(controls, control);
		};

		form.$setValidity = function(validationToken, isValid, control) {
			var queue = errors[validationToken];
			if (isValid) {
				if (queue) {
					arrayRemove(queue, control);
					if (!queue.length) {
						invalidCount--;
						if (!invalidCount) {
							toggleValidCss(element, isValid);
							form.$valid = true;
							form.$invalid = false;
						}
						//errors[validationToken] = false;
						delete errors[validationToken];
						toggleValidCss(element, true, validationToken);
					}
				}
			} else {
				if (!invalidCount) {
					toggleValidCss(element, isValid);
				}
				if (queue) {
					if (includes(queue, control))
						return;
				} else {
					errors[validationToken] = queue = [];
					invalidCount++;
					toggleValidCss(element, false, validationToken);
				}
				queue.push(control);
				form.$valid = false;
				form.$invalid = true;
			}
		};

		form.$setDirty = function() {
			element.removeClass(PRISTINE_CLASS).addClass(DIRTY_CLASS);
			form.$dirty = true;
			form.$pristine = false;
		};

		/**
		 * @vxdoc function
		 * @name v.directive:form.FormController#$setPristine
		 * @methodOf v.directive:form.FormController
		 *
		 * @description
		 * Sets the form to its pristine state.
		 *
		 * This method can be called to remove the 'v-dirty' class and set the form to its pristine
		 * state (v-pristine class). This method will also propagate to all the controls contained
		 * in this form.
		 *
		 * Setting a form back to a pristine state is often useful when we want to 'reuse' a form after
		 * saving or resetting it.
		 */
		form.$setPristine = function() {
			element.removeClass(DIRTY_CLASS).addClass(PRISTINE_CLASS);
			form.$dirty = false;
			form.$pristine = true;
			forEach(controls, function(control) {
				control.$setPristine();
			});
		};

	}

	/**
	 * @vxdoc directive
	 * @name vx.directive:vForm
	 * @restrict EAC
	 *
	 * @description
	 * Nestable alias of {@link vx.directive:form `form`} directive. HTML
	 * does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a
	 * sub-group of controls needs to be determined.
	 *
	 * @param {string=} name|vForm Name of the form. If specified, the form controller will be published into
	 *                       related scope, under this name.
	 *
	 */

	/**
	 * @vxdoc directive
	 * @name vx.directive:form
	 * @restrict E
	 *
	 * @description
	 * Directive that instantiates
	 * {@link vx.directive:form.FormController FormController}.
	 *
	 * If `name` attribute is specified, the form controller is published onto the current scope under
	 * this name.
	 *
	 * # Alias: {@link vx.directive:vForm `vForm`}
	 *
	 * In vx forms can be nested. This means that the outer form is valid when all of the child
	 * forms are valid as well. However browsers do not allow nesting of `<form>` elements, for this
	 * reason vx provides {@link vx.directive:vForm `vForm`} alias
	 * which behaves identical to `<form>` but allows form nesting.
	 *
	 *
	 * # CSS classes
	 *  - `v-valid` Is set if the form is valid.
	 *  - `v-invalid` Is set if the form is invalid.
	 *  - `v-pristine` Is set if the form is pristine.
	 *  - `v-dirty` Is set if the form is dirty.
	 *
	 *
	 * # Submitting a form and preventing default action
	 *
	 * Since the role of forms in client-side VX applications is different than in classical
	 * roundtrip apps, it is desirable for the browser not to translate the form submission into a full
	 * page reload that sends the data to the server. Instead some javascript logic should be triggered
	 * to handle the form submission in application specific way.
	 *
	 * For this reason, VX prevents the default action (form submission to the server) unless the
	 * `<form>` element has an `action` attribute specified.
	 *
	 * You can use one of the following two ways to specify what javascript method should be called when
	 * a form is submitted:
	 *
	 * - {@link vx.directive:vSubmit vSubmit} directive on the form element
	 * - {@link vx.directive:vClick vClick} directive on the first
	 *  button or input field of type submit (input[type=submit])
	 *
	 * To prevent double execution of the handler, use only one of vSubmit or vClick directives. This
	 * is because of the following form submission rules coming from the html spec:
	 *
	 * - If a form has only one input field then hitting enter in this field triggers form submit
	 * (`vSubmit`)
	 * - if a form has has 2+ input fields and no buttons or input[type=submit] then hitting enter
	 * doesn't trigger submit
	 * - if a form has one or more input fields and one or more buttons or input[type=submit] then
	 * hitting enter in any of the input fields will trigger the click handler on the *first* button or
	 * input[type=submit] (`vClick`) *and* a submit handler on the enclosing form (`vSubmit`)
	 *
	 * @param {string=} name Name of the form. If specified, the form controller will be published into
	 *                       related scope, under this name.
	 *
	 * @example
	 <doc:example>
	 <doc:source>
	 <script>
	 function Ctrl($scope) {
	 $scope.userType = 'guest';
	 }
	 </script>
	 <form name="myForm" v-controller="Ctrl">
	 userType: <input name="input" v-model="userType" required>
	 <span class="error" v-show="myForm.input.$error.required">Required!</span><br>
	 <tt>userType = {{userType}}</tt><br>
	 <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br>
	 <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br>
	 <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
	 <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
	 </form>
	 </doc:source>
	 <doc:scenario>
	 it('should initialize to model', function() {
	 expect(binding('userType')).toEqual('guest');
	 expect(binding('myForm.input.$valid')).toEqual('true');
	 });

	 it('should be invalid if empty', function() {
	 input('userType').enter('');
	 expect(binding('userType')).toEqual('');
	 expect(binding('myForm.input.$valid')).toEqual('false');
	 });
	 </doc:scenario>
	 </doc:example>
	 */
	function formDirectiveFactory(isVForm) {
		factory.$inject = ['$$remote'];
		function factory($$remote) {
			var formDirective = {
				name : 'form',
				restrict : 'E',
				controller : FormController,
				compile : function() {
					return {
						pre : function(scope, formElement, attr, controller) {
							if (!attr.action) {
								formElement.bind('submit', function(event) {
									event.preventDefault();
									//event.stopPropagation();
								});
							}

							if (attr.action) {
								var parent = attr.parent === 'true', model = attr.model || '$result';
								var act = trim(attr.action);
								var $remote = $$remote(formElement, true);
								formElement.bind('submit', function(event) {
									// forbid cascade submit
									if (event.target !== formElement[0]) {
										var formCtrl0 = jqLite(event.target).controller('form');
										if (controller !== formCtrl0)
											return;
									}
									if (!controller.$getError(parent)) {
										//scope.$apply(function() {
										var data = controller.$getData(parent);
										var q = $remote.post(act, data, model);
										if (attr.href) {
											var target = trim(attr.href);
											q.forward(attr.target || formElement.controller('vViewport'), target);
										}
										//}, isVForm ? 'v-form' : 'form');
									}
									event.preventDefault();
									//event.stopPropagation();
								});
							}

							var page = formElement.controller('vPage');
							if (page)
								page.$addForm(controller);

							var bind = controller.$bind = function() {
								var fname = controller.$name;
								if (fname) {
									if (scope[fname])
										throw vError(114, 'scope has duplicated form name: {0}', fname);
									scope[fname] = controller;
									return true;
								}
								return false;
							};

							if (bind()) {
								var attachFn = function attachFn(key) {
									return function(value) {
										var oldName = controller.$name;
										if (oldName === value)
											return;
										if (oldName/* && controller === scope[oldName]*/) {
											delete scope[oldName];
										}
										if (scope[value])
											throw vError(115, 'scope has duplicated form name: {0}', value);
										scope[value] = controller;
										controller.$name = value;
									};
								};
								if (!isVForm)
									attr.$observe('name', attachFn('name'));
								else
									attr.$observe('vForm', attachFn('vForm'));
							}

							var unbind = controller.$unbind = function() {
								var name = controller.$name;
								if (name/* && controller === scope[name]*/) {
									delete scope[name];
								}
							};

							formElement.bind('$destroy', function() {
								unbind();
								if (page)
									page.$removeForm(controller);
								//stop propagating child destruction handlers upwards
								//extend(controller, nullFormCtrl);
								cleanupClosure(controller);
							});

						}
					};
				}
			};
			return isVForm ? extend(copy(formDirective), {
				restrict : 'EAC'
			}) : formDirective;
		}

		return factory;
	}

	var formDirective = formDirectiveFactory();
	//var vFormDirective = formDirectiveFactory(true);

	/**
	 * @vxdoc directive
	 * @name vx.directive:textarea
	 * @restrict E
	 *
	 * @description
	 * HTML textarea element control with vx data-binding. The data-binding and validation
	 * properties of this element are exactly the same as those of the
	 * {@link vx.directive:input input element}.
	 *
	 * @param {string} vModel Assignable vx expression to data-bind to.
	 * @param {string=} name Property name of the form under which the control is published.
	 * @param {string=} required Adds `required` validation error key if the value is not entered.
	 * @param {string=} vRequired Adds `required` attribute and `required` validation constraint to
	 *    the element when the vRequired expression evaluates to true. Use `vRequired` instead of
	 *    `required` when you want to data-bind to the `required` attribute.
	 * @param {number=} vMinlength Sets `minlength` validation error key if the value is shorter than
	 *    minlength.
	 * @param {number=} vMaxlength Sets `maxlength` validation error key if the value is longer than
	 *    maxlength.
	 * @param {string=} vPattern Sets `pattern` validation error key if the value does not match the
	 *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
	 *    patterns defined as scope expressions.
	 * @param {string=} vChange VX expression to be executed when input changes due to user
	 *    interaction with the input element.
	 */

	/**
	 * @vxdoc directive
	 * @name vx.directive:input
	 * @restrict E
	 *
	 * @description
	 * HTML input element control with vx data-binding. Input control follows HTML5 input types
	 * and polyfills the HTML5 validation behavior for older browsers.
	 *
	 * @param {string} vModel Assignable vx expression to data-bind to.
	 * @param {string=} name Property name of the form under which the control is published.
	 * @param {number=} vMinlength Sets `minlength` validation error key if the value is shorter than
	 *    minlength.
	 * @param {number=} vMaxlength Sets `maxlength` validation error key if the value is longer than
	 *    maxlength.
	 * @param {string=} vPattern Sets `pattern` validation error key if the value does not match the
	 *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
	 *    patterns defined as scope expressions.
	 * @param {string=} vChange VX expression to be executed when input changes due to user
	 *    interaction with the input element.
	 *
	 * @example
	 <doc:example>
	 <doc:source>
	 <script>
	 function Ctrl($scope) {
	 $scope.user = {name: 'guest', last: 'visitor'};
	 }
	 </script>
	 <div v-controller="Ctrl">
	 <form name="myForm">
	 User name: <input type="text" name="userName" v-model="user.name" required>
	 <span class="error" v-show="myForm.userName.$error.required">
	 Required!</span><br>
	 Last name: <input type="text" name="lastName" v-model="user.last"
	 v-minlength="3" v-maxlength="10">
	 <span class="error" v-show="myForm.lastName.$error.minlength">
	 Too short!</span>
	 <span class="error" v-show="myForm.lastName.$error.maxlength">
	 Too long!</span><br>
	 </form>
	 <hr>
	 <tt>user = {{user}}</tt><br/>
	 <tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br>
	 <tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br>
	 <tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br>
	 <tt>myForm.lastName.$error = {{myForm.lastName.$error}}</tt><br>
	 <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
	 <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
	 <tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt><br>
	 <tt>myForm.$error.maxlength = {{!!myForm.$error.maxlength}}</tt><br>
	 </div>
	 </doc:source>
	 <doc:scenario>
	 it('should initialize to model', function() {
	 expect(binding('user')).toEqual('{"name":"guest","last":"visitor"}');
	 expect(binding('myForm.userName.$valid')).toEqual('true');
	 expect(binding('myForm.$valid')).toEqual('true');
	 });

	 it('should be invalid if empty when required', function() {
	 input('user.name').enter('');
	 expect(binding('user')).toEqual('{"last":"visitor"}');
	 expect(binding('myForm.userName.$valid')).toEqual('false');
	 expect(binding('myForm.$valid')).toEqual('false');
	 });

	 it('should be valid if empty when min length is set', function() {
	 input('user.last').enter('');
	 expect(binding('user')).toEqual('{"name":"guest","last":""}');
	 expect(binding('myForm.lastName.$valid')).toEqual('true');
	 expect(binding('myForm.$valid')).toEqual('true');
	 });

	 it('should be invalid if less than required min length', function() {
	 input('user.last').enter('xx');
	 expect(binding('user')).toEqual('{"name":"guest"}');
	 expect(binding('myForm.lastName.$valid')).toEqual('false');
	 expect(binding('myForm.lastName.$error')).toMatch(/minlength/);
	 expect(binding('myForm.$valid')).toEqual('false');
	 });

	 it('should be invalid if longer than max length', function() {
	 input('user.last').enter('some ridiculously long name');
	 expect(binding('user'))
	 .toEqual('{"name":"guest"}');
	 expect(binding('myForm.lastName.$valid')).toEqual('false');
	 expect(binding('myForm.lastName.$error')).toMatch(/maxlength/);
	 expect(binding('myForm.$valid')).toEqual('false');
	 });
	 </doc:scenario>
	 </doc:example>
	 */
	inputDirective.$inject = ['$browser', '$sniffer', '$validation', '$log'];
	function inputDirective($browser, $sniffer, $validation, $log) {

		var inputType = {

			/**
			 * @vxdoc inputType
			 * @name vx.directive:input.text
			 *
			 * @description
			 * Standard HTML text input with vx data binding.
			 *
			 * @param {string} vModel Assignable vx expression to data-bind to.
			 * @param {string=} name Property name of the form under which the control is published.
			 * @param {string=} required Adds `required` validation error key if the value is not entered.
			 * @param {string=} vRequired Adds `required` attribute and `required` validation constraint to
			 *    the element when the vRequired expression evaluates to true. Use `vRequired` instead of
			 *    `required` when you want to data-bind to the `required` attribute.
			 * @param {number=} vMinlength Sets `minlength` validation error key if the value is shorter than
			 *    minlength.
			 * @param {number=} vMaxlength Sets `maxlength` validation error key if the value is longer than
			 *    maxlength.
			 * @param {string=} vPattern Sets `pattern` validation error key if the value does not match the
			 *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
			 *    patterns defined as scope expressions.
			 * @param {string=} vChange VX expression to be executed when input changes due to user
			 *    interaction with the input element.
			 * @param {boolean=} [vTrim=true] If set to false VX will not automatically trimming the
			 *    input.
			 *
			 * @example
			 <doc:example>
			 <doc:source>
			 <script>
			 function Ctrl($scope) {
			 $scope.text = 'guest';
			 $scope.word = /^\s*\w*\s*$/;
			 }
			 </script>
			 <form name="myForm" v-controller="Ctrl">
			 Single word: <input type="text" name="input" v-model="text"
			 v-pattern="word" required v-trim="false">
			 <span class="error" v-show="myForm.input.$error.required">
			 Required!</span>
			 <span class="error" v-show="myForm.input.$error.pattern">
			 Single word only!</span>

			 <tt>text = {{text}}</tt><br/>
			 <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
			 <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
			 <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
			 <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
			 </form>
			 </doc:source>
			 <doc:scenario>
			 it('should initialize to model', function() {
			 expect(binding('text')).toEqual('guest');
			 expect(binding('myForm.input.$valid')).toEqual('true');
			 });

			 it('should be invalid if empty', function() {
			 input('text').enter('');
			 expect(binding('text')).toEqual('');
			 expect(binding('myForm.input.$valid')).toEqual('false');
			 });

			 it('should be invalid if multi word', function() {
			 input('text').enter('hello world');
			 expect(binding('myForm.input.$valid')).toEqual('false');
			 });

			 it('should not be trimmed', function() {
			 input('text').enter('untrimmed ');
			 expect(binding('text')).toEqual('untrimmed ');
			 expect(binding('myForm.input.$valid')).toEqual('true');
			 });
			 </doc:scenario>
			 </doc:example>
			 */
			'text' : textInputType,

			/**
			 * @vxdoc inputType
			 * @name vx.directive:input.number
			 *
			 * @description
			 * Text input with number validation and transformation. Sets the `number` validation
			 * error if not a valid number.
			 *
			 * @param {string} vModel Assignable vx expression to data-bind to.
			 * @param {string=} name Property name of the form under which the control is published.
			 * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
			 * @param {string=} max Sets the `max` validation error key if the value entered is greater than `min`.
			 * @param {string=} required Adds `required` validation error key if the value is not entered.
			 * @param {string=} vRequired Adds `required` attribute and `required` validation constraint to
			 *    the element when the vRequired expression evaluates to true. Use `vRequired` instead of
			 *    `required` when you want to data-bind to the `required` attribute.
			 * @param {number=} vMinlength Sets `minlength` validation error key if the value is shorter than
			 *    minlength.
			 * @param {number=} vMaxlength Sets `maxlength` validation error key if the value is longer than
			 *    maxlength.
			 * @param {string=} vPattern Sets `pattern` validation error key if the value does not match the
			 *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
			 *    patterns defined as scope expressions.
			 * @param {string=} vChange VX expression to be executed when input changes due to user
			 *    interaction with the input element.
			 *
			 * @example
			 <doc:example>
			 <doc:source>
			 <script>
			 function Ctrl($scope) {
			 $scope.value = 12;
			 }
			 </script>
			 <form name="myForm" v-controller="Ctrl">
			 Number: <input type="number" name="input" v-model="value"
			 min="0" max="99" required>
			 <span class="error" v-show="myForm.list.$error.required">
			 Required!</span>
			 <span class="error" v-show="myForm.list.$error.number">
			 Not valid number!</span>
			 <tt>value = {{value}}</tt><br/>
			 <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
			 <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
			 <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
			 <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
			 </form>
			 </doc:source>
			 <doc:scenario>
			 it('should initialize to model', function() {
			 expect(binding('value')).toEqual('12');
			 expect(binding('myForm.input.$valid')).toEqual('true');
			 });

			 it('should be invalid if empty', function() {
			 input('value').enter('');
			 expect(binding('value')).toEqual('');
			 expect(binding('myForm.input.$valid')).toEqual('false');
			 });

			 it('should be invalid if over max', function() {
			 input('value').enter('123');
			 expect(binding('value')).toEqual('');
			 expect(binding('myForm.input.$valid')).toEqual('false');
			 });
			 </doc:scenario>
			 </doc:example>
			 */
			'number' : numberInputType,

			/**
			 * @vxdoc inputType
			 * @name vx.directive:input.url
			 *
			 * @description
			 * Text input with URL validation. Sets the `url` validation error key if the content is not a
			 * valid URL.
			 *
			 * @param {string} vModel Assignable vx expression to data-bind to.
			 * @param {string=} name Property name of the form under which the control is published.
			 * @param {string=} required Adds `required` validation error key if the value is not entered.
			 * @param {string=} vRequired Adds `required` attribute and `required` validation constraint to
			 *    the element when the vRequired expression evaluates to true. Use `vRequired` instead of
			 *    `required` when you want to data-bind to the `required` attribute.
			 * @param {number=} vMinlength Sets `minlength` validation error key if the value is shorter than
			 *    minlength.
			 * @param {number=} vMaxlength Sets `maxlength` validation error key if the value is longer than
			 *    maxlength.
			 * @param {string=} vPattern Sets `pattern` validation error key if the value does not match the
			 *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
			 *    patterns defined as scope expressions.
			 * @param {string=} vChange VX expression to be executed when input changes due to user
			 *    interaction with the input element.
			 *
			 * @example
			 <doc:example>
			 <doc:source>
			 <script>
			 function Ctrl($scope) {
			 $scope.text = 'http://google.com';
			 }
			 </script>
			 <form name="myForm" v-controller="Ctrl">
			 URL: <input type="url" name="input" v-model="text" required>
			 <span class="error" v-show="myForm.input.$error.required">
			 Required!</span>
			 <span class="error" v-show="myForm.input.$error.url">
			 Not valid url!</span>
			 <tt>text = {{text}}</tt><br/>
			 <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
			 <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
			 <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
			 <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
			 <tt>myForm.$error.url = {{!!myForm.$error.url}}</tt><br/>
			 </form>
			 </doc:source>
			 <doc:scenario>
			 it('should initialize to model', function() {
			 expect(binding('text')).toEqual('http://google.com');
			 expect(binding('myForm.input.$valid')).toEqual('true');
			 });

			 it('should be invalid if empty', function() {
			 input('text').enter('');
			 expect(binding('text')).toEqual('');
			 expect(binding('myForm.input.$valid')).toEqual('false');
			 });

			 it('should be invalid if not url', function() {
			 input('text').enter('xxx');
			 expect(binding('myForm.input.$valid')).toEqual('false');
			 });
			 </doc:scenario>
			 </doc:example>
			 */
			'url' : urlInputType,

			/**
			 * @vxdoc inputType
			 * @name vx.directive:input.email
			 *
			 * @description
			 * Text input with email validation. Sets the `email` validation error key if not a valid email
			 * address.
			 *
			 * @param {string} vModel Assignable vx expression to data-bind to.
			 * @param {string=} name Property name of the form under which the control is published.
			 * @param {string=} required Adds `required` validation error key if the value is not entered.
			 * @param {string=} vRequired Adds `required` attribute and `required` validation constraint to
			 *    the element when the vRequired expression evaluates to true. Use `vRequired` instead of
			 *    `required` when you want to data-bind to the `required` attribute.
			 * @param {number=} vMinlength Sets `minlength` validation error key if the value is shorter than
			 *    minlength.
			 * @param {number=} vMaxlength Sets `maxlength` validation error key if the value is longer than
			 *    maxlength.
			 * @param {string=} vPattern Sets `pattern` validation error key if the value does not match the
			 *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
			 *    patterns defined as scope expressions.
			 * @param {string=} vChange VX expression to be executed when input changes due to user
			 *    interaction with the input element.
			 *
			 * @example
			 <doc:example>
			 <doc:source>
			 <script>
			 function Ctrl($scope) {
			 $scope.text = 'me@example.com';
			 }
			 </script>
			 <form name="myForm" v-controller="Ctrl">
			 Email: <input type="email" name="input" v-model="text" required>
			 <span class="error" v-show="myForm.input.$error.required">
			 Required!</span>
			 <span class="error" v-show="myForm.input.$error.email">
			 Not valid email!</span>
			 <tt>text = {{text}}</tt><br/>
			 <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
			 <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
			 <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
			 <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
			 <tt>myForm.$error.email = {{!!myForm.$error.email}}</tt><br/>
			 </form>
			 </doc:source>
			 <doc:scenario>
			 it('should initialize to model', function() {
			 expect(binding('text')).toEqual('me@example.com');
			 expect(binding('myForm.input.$valid')).toEqual('true');
			 });

			 it('should be invalid if empty', function() {
			 input('text').enter('');
			 expect(binding('text')).toEqual('');
			 expect(binding('myForm.input.$valid')).toEqual('false');
			 });

			 it('should be invalid if not email', function() {
			 input('text').enter('xxx');
			 expect(binding('myForm.input.$valid')).toEqual('false');
			 });
			 </doc:scenario>
			 </doc:example>
			 */
			'email' : emailInputType,

			/**
			 * @vxdoc inputType
			 * @name vx.directive:input.radio
			 *
			 * @description
			 * HTML radio button.
			 *
			 * @param {string} vModel Assignable vx expression to data-bind to.
			 * @param {string} value The value to which the expression should be set when selected.
			 * @param {string=} name Property name of the form under which the control is published.
			 * @param {string=} vChange VX expression to be executed when input changes due to user
			 *    interaction with the input element.
			 *
			 * @example
			 <doc:example>
			 <doc:source>
			 <script>
			 function Ctrl($scope) {
			 $scope.color = 'blue';
			 }
			 </script>
			 <form name="myForm" v-controller="Ctrl">
			 <input type="radio" v-model="color" value="red">  Red <br/>
			 <input type="radio" v-model="color" value="green"> Green <br/>
			 <input type="radio" v-model="color" value="blue"> Blue <br/>
			 <tt>color = {{color}}</tt><br/>
			 </form>
			 </doc:source>
			 <doc:scenario>
			 it('should change state', function() {
			 expect(binding('color')).toEqual('blue');

			 input('color').select('red');
			 expect(binding('color')).toEqual('red');
			 });
			 </doc:scenario>
			 </doc:example>
			 */
			'radio' : radioInputType,

			/**
			 * @vxdoc inputType
			 * @name vx.directive:input.checkbox
			 *
			 * @description
			 * HTML checkbox.
			 *
			 * @param {string} vModel Assignable vx expression to data-bind to.
			 * @param {string=} name Property name of the form under which the control is published.
			 * @param {string=} vTrueValue The value to which the expression should be set when selected.
			 * @param {string=} vFalseValue The value to which the expression should be set when not selected.
			 * @param {string=} vChange VX expression to be executed when input changes due to user
			 *    interaction with the input element.
			 *
			 * @example
			 <doc:example>
			 <doc:source>
			 <script>
			 function Ctrl($scope) {
			 $scope.value1 = true;
			 $scope.value2 = 'YES'
			 }
			 </script>
			 <form name="myForm" v-controller="Ctrl">
			 Value1: <input type="checkbox" v-model="value1"> <br/>
			 Value2: <input type="checkbox" v-model="value2"
			 v-true-value="YES" v-false-value="NO"> <br/>
			 <tt>value1 = {{value1}}</tt><br/>
			 <tt>value2 = {{value2}}</tt><br/>
			 </form>
			 </doc:source>
			 <doc:scenario>
			 it('should change state', function() {
			 expect(binding('value1')).toEqual('true');
			 expect(binding('value2')).toEqual('YES');

			 input('value1').check();
			 input('value2').check();
			 expect(binding('value1')).toEqual('false');
			 expect(binding('value2')).toEqual('NO');
			 });
			 </doc:scenario>
			 </doc:example>
			 */
			'checkbox' : checkboxInputType,

			'hidden' : hiddenInputType,
			'submit' : submitInputType,
			'reset' : resetInputType,
			'button' : noop

			//'password' : noop,
			//'image' : noop,
			//'file' : noop,
			//'range' : noop,

			//color
			//date
			//datetime
			//datetime-local
			//month
			//week
			//time
			//search

		};

		function getPropertyName(e) {
			return e.originalEvent ? e.originalEvent.propertyName : e.propertyName;
		}

		function textInputType(scope, element, attr, ctrl) {
			var await = attr.await ? int(attr.await) : 300;
			var listener = function(event) {
				var value = element.val();
				// By default we will trim the value
				// If the attribute v-trim exists we will avoid trimming
				// e.g. <input v-model="foo" v-trim="false">
				if (toBoolean(attr.vTrim || 'T')) {
					value = trim(value);
				}

				if (ctrl.$viewValue !== value) {
					scope.$apply(function() {
						ctrl.$setViewValue(value);
					}, ':text');
				}
			};

			if (await)
				listener = $browser.debounce(listener, await);

			// if the browser does support "input" event, we are fine - except on IE9 which doesn't fire the
			// input event on backspace, delete or cut
			if ($sniffer.hasEvent('input'))
				element.bind('input', listener);
			else {
				/*
				 element.bind('keydown', function(event) {
				 var key = event.keyCode;
				 // ignore command            modifiers                   arrows
				 if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40))
				 return;
				 listener();
				 });
				 // if user paste into input using mouse, we need "change" event to catch it
				 if (msie <= 9) {
				 //***IMPORTANT: jimmy element.val() will trigger propertychange event, so skip it
				 var inVal, __val = element.val;
				 element.val = function(value) {
				 if (value === undefined)
				 return __val.call(this);
				 try {
				 inVal = true;
				 return __val.call(this, value);
				 } finally {
				 inVal = false;
				 }
				 };
				 element.data('input.val', element.val());
				 var fixInput = function(e) {
				 if (inVal || getPropertyName(e) !== 'value')
				 return;
				 if (element.val() !== element.data('input.val')) {
				 element.data('input.val', element.val());
				 listener();
				 }
				 };
				 if (msie > 8)//***jimmy: on IE 9, direct use attachEvent, jQuery bind not work!!!
				 element[0].attachEvent('onpropertychange', fixInput);
				 else
				 element.bind('propertychange', fixInput);
				 } else {
				 element.bind('change', listener);
				 }*/

				element.bind('keydown', function(event) {
					var key = event.keyCode;

					// ignore
					//    command            modifiers                   arrows
					if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40))
						return;
					listener(event);
				});

				// if user paste into input using mouse, we need "change" event to catch it
				element.bind('change', listener);

				// if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
				if ($sniffer.hasEvent('paste')) {
					element.bind('paste cut', listener);
				}
			}

			ctrl.$render = function() {
				element.val(isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue);
			};

			ctrl.$reset = function() {
				element.val('');
				ctrl.$setViewValue('');
			};

			// min length validator
			if (attr.vMinlength) {
				var minlength = int(attr.vMinlength);
				$validation.use(ctrl, 'minlength', minlength);
			}

			// max length validator
			if (attr.vMaxlength) {
				var maxlength = int(attr.vMaxlength);
				$validation.use(ctrl, 'maxlength', maxlength);
			}

			// pattern validator
			var pattern = attr.vPattern, patternObj, match;
			if (pattern) {
				match = pattern.match(/^\/(.*)\/([gim]*)$/);
				if (match) {
					patternObj = new RegExp(match[1], match[2]);
				} else {
					patternObj = new RegExp(pattern);
				}
				$validation.use(ctrl, 'pattern', patternObj);
			}

		}

		function numberInputType(scope, element, attr, ctrl) {
			textInputType(scope, element, attr, ctrl);

			$validation.use(ctrl, 'number');

			if (attr.min) {
				var min = parseFloat(attr.min);
				$validation.use(ctrl, 'min', min);
			}

			if (attr.max) {
				var max = parseFloat(attr.max);
				$validation.use(ctrl, 'max', max);
			}

		}

		function urlInputType(scope, element, attr, ctrl) {
			textInputType(scope, element, attr, ctrl);

			$validation.use(ctrl, 'url');
		}

		function emailInputType(scope, element, attr, ctrl) {
			textInputType(scope, element, attr, ctrl);

			$validation.use(ctrl, 'email');
		}

		function radioInputType(scope, element, attr, ctrl) {
			// make the name unique, if not defined
			if (isUndefined(attr.name)) {
				element.attr('name', nextUid(inputId));
			}

			element.bind('click', function() {
				if (element[0].checked) {
					scope.$apply(function() {
						ctrl.$setViewValue(attr.value);
					}, ':radio');
				}
			});

			ctrl.$render = function() {
				var value = attr.value;
				element[0].checked = (value == ctrl.$viewValue);
			};

			ctrl.$reset = function() {
				element[0].checked = false;
				ctrl.$setViewValue(null);
			};

			attr.$observe('value', ctrl.$render);
		}

		function checkboxInputType(scope, element, attr, ctrl) {
			var trueValue = attr.vTrueValue, falseValue = attr.vFalseValue;

			if (!isString(trueValue))
				trueValue = true;
			if (!isString(falseValue))
				falseValue = false;

			element.bind('click', function() {
				scope.$apply(function() {
					ctrl.$setViewValue(element[0].checked);
				}, ':checkbox');
			});

			ctrl.$render = function() {
				element[0].checked = ctrl.$viewValue;
			};

			ctrl.$reset = function() {
				element[0].checked = false;
				ctrl.$setViewValue(null);
			};

			ctrl.$formatters.push(function(value) {
				return value === trueValue;
			});

			ctrl.$parsers.push(function(value) {
				if (value === null)
					return null;
				// for reset
				return value ? trueValue : falseValue;
			});
		}

		function hiddenInputType(scope, element, attr, ctrl) {
			// just model -> view
			ctrl.$render = function() {
				element.val(isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue);
			};
		}

		function submitInputType(scope, element, attr, ctrl) {
			var parentForm = element.parent().controller('form');
			if (!parentForm)
				return;
			var await = attr.await ? int(attr.await) : 1000;
			// just view -> model
			var handler = function() {
				if (ctrl) {
					scope.$apply(function() {
						ctrl.$setViewValue(attr.value);
					}, ':submit');
				}
				//element.trigger('submit');
				parentForm.$submit();
			};

			if (await) {
				var h = handler;
				handler = $browser.debounce(function() {
					h();
					element.addClass('v-submitting');
				}, await, function() {
					element.removeClass('v-submitting');
				}, true);
			}

			element.bind('click', function(event) {
				event.preventDefault();
				handler();
			});
		}

		function resetInputType(scope, element, attr) {
			var parentForm = element.parent().controller('form');
			if (!parentForm)
				return;
			element.bind('click', function(event) {
				scope.$apply(function() {
					parentForm.$clearData();
					parentForm.$setPristine();
				}, ':reset');
				event.preventDefault();
			});
		}

		return {
			restrict : 'E',
			require : '?vModel',
			link : function(scope, element, attr, ctrl) {
				if (ctrl) {
					var fn;
					if (_nodeName(element) === 'BUTTON')
						fn = inputType[lowercase(attr.type)] || inputType.submit;
					else
						fn = inputType[lowercase(attr.type)] || inputType.text;
					if (fn)
						fn(scope, element, attr, ctrl);
				} else if (attr.type === 'submit') {
					inputType.submit(scope, element, attr);
				} else if (attr.type === 'reset') {
					inputType.reset(scope, element, attr);
				}
			}
		};
	}

	/**
	 * @vxdoc object
	 * @name vx.directive:vModel.vModelController
	 *
	 * @property {string} $viewValue Actual string value in the view.
	 * @property {*} $modelValue The value in the model, that the control is bound to.
	 * @property {Array.<Function>} $parsers Whenever the control reads value from the DOM, it executes
	 *     all of these functions to sanitize / convert the value as well as validate.
	 *
	 * @property {Array.<Function>} $formatters Whenever the model value changes, it executes all of
	 *     these functions to convert the value as well as validate.
	 *
	 * @property {Object} $error An object hash with all errors as keys.
	 *
	 * @property {boolean} $pristine True if user has not interacted with the control yet.
	 * @property {boolean} $dirty True if user has already interacted with the control.
	 * @property {boolean} $valid True if there is no error.
	 * @property {boolean} $invalid True if at least one error on the control.
	 *
	 * @description
	 *
	 * `vModelController` provides API for the `v-model` directive. The controller contains
	 * services for data-binding, validation, CSS update, value formatting and parsing. It
	 * specifically does not contain any logic which deals with DOM rendering or listening to
	 * DOM events. The `vModelController` is meant to be extended by other directives where, the
	 * directive provides DOM manipulation and the `vModelController` provides the data-binding.
	 *
	 * This example shows how to use `vModelController` with a custom control to achieve
	 * data-binding. Notice how different directives (`contenteditable`, `v-model`, and `required`)
	 * collaborate together to achieve the desired result.
	 *
	 * <example module="customControl">
	 <file name="style.css">
	 [contenteditable] {
	 border: 1px solid black;
	 background-color: white;
	 min-height: 20px;
	 }

	 .v-invalid {
	 border: 1px solid red;
	 }

	 </file>
	 <file name="script.js">
	 vx.module('customControl', []).
	 directive('contenteditable', function() {
	 return {
	 restrict: 'A', // only activate on element attribute
	 require: '?vModel', // get a hold of vModelController
	 link: function(scope, element, attrs, vModel) {
	 if(!vModel) return; // do nothing if no v-model

	 // Specify how UI should be updated
	 vModel.$render = function() {
	 element.html(vModel.$viewValue || '');
	 };

	 // Listen for change events to enable binding
	 element.bind('blur keyup change', function() {
	 scope.$apply(read);
	 });
	 read(); // initialize

	 // Write data to the model
	 function read() {
	 vModel.$setViewValue(element.html());
	 }
	 }
	 };
	 });
	 </file>
	 <file name="index.html">
	 <form name="myForm">
	 <div contenteditable
	 name="myWidget" v-model="userContent"
	 required>Change me!</div>
	 <span v-show="myForm.myWidget.$error.required">Required!</span>
	 <hr>
	 <textarea v-model="userContent"></textarea>
	 </form>
	 </file>
	 <file name="scenario.js">
	 it('should data-bind and become invalid', function() {
	 var contentEditable = element('[contenteditable]');

	 expect(contentEditable.text()).toEqual('Change me!');
	 input('userContent').enter('');
	 expect(contentEditable.text()).toEqual('');
	 expect(contentEditable.prop('className')).toMatch(/v-invalid-required/);
	 });
	 </file>
	 * </example>
	 *
	 */
	vModelController.$inject = ['$scope', /*'$exceptionHandler',*/'$log', '$attrs', '$element', '$parse', '$injector'];
	function vModelController($scope, /*$exceptionHandler,*/$log, $attr, $element, $parse, $injector) {
		/*jshint validthis:true*/
		this.$viewValue = Number.NaN;
		this.$modelValue = Number.NaN;
		this.$parsers = [];
		this.$formatters = [];
		this.$$parsers = [];
		this.$$formatters = [];
		this.$viewChangeListeners = [];
		this.$pristine = true;
		this.$dirty = false;
		this.$valid = true;
		this.$invalid = false;
		this.$name = $attr.name;

		var vModelGet = $parse($attr.vModel), vModelSet = vModelGet.assign;

		if (!vModelSet) {
			throw vError(116, "vModel error! Expression '{0}' is non-assignable. Element: {1}", $attr.vModel, startingTag($element));
		}

		/**
		 * @vxdoc function
		 * @name vx.directive:vModel.vModelController#$render
		 * @methodOf vx.directive:vModel.vModelController
		 *
		 * @description
		 * Called when the view needs to be updated. It is expected that the user of the v-model
		 * directive will implement this method.
		 */
		this.$render = noop;

		this.$reset = noop;

		var parentForm = $element.controller('form') || nullFormCtrl, invalidCount = 0, // used to easily determine if we are valid
		$error = this.$error = {};
		// keep invalid keys here

		var parentCtrl = $element.parent().controller('vModel');
		if (parentCtrl) {
			this.$parentModel = true;
			parentCtrl.$virtual = true;
		}

		this.$destroy = function() {
			$scope = null;
			$element = null;
		};

		// Setup initial state of the control
		$element.addClass(PRISTINE_CLASS);
		toggleValidCss($element, true);

		// convenience method for easy toggling of classes
		function toggleValidCss($element, isValid, validationErrorKey) {
			validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
			$element.removeClass(( isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey).addClass(( isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey);
		}

		/**
		 * @vxdoc function
		 * @name vx.directive:vModel.vModelController#$setValidity
		 * @methodOf vx.directive:vModel.vModelController
		 *
		 * @description
		 * Change the validity state, and notifies the form when the control changes validity. (i.e. it
		 * does not notify form if given validator is already marked as invalid).
		 *
		 * This method should be called by validators - i.e. the parser or formatter functions.
		 *
		 * @param {string} validationErrorKey Name of the validator. the `validationErrorKey` will assign
		 *        to `$error[validationErrorKey]=isValid` so that it is available for data-binding.
		 *        The `validationErrorKey` should be in camelCase and will get converted into dash-case
		 *        for class name. Example: `myError` will result in `v-valid-my-error` and `v-invalid-my-error`
		 *        class and can be bound to as  `{{someForm.someControl.$error.myError}}` .
		 * @param {boolean} isValid Whether the current state is valid (true) or invalid (false).
		 */
		this.$setValidity = function(validationErrorKey, isValid) {
			var nValid = isValid === null ? null : !isValid;
			isValid = isValid === null || !!isValid;
			if ($error[validationErrorKey] === nValid)
				return;

			if (isValid) {
				if ($error[validationErrorKey] === null || $error[validationErrorKey])
					invalidCount--;
				if (!invalidCount) {
					toggleValidCss($element, true);
					this.$valid = true;
					this.$invalid = false;
				}
			} else {
				toggleValidCss($element, false);
				this.$invalid = true;
				this.$valid = false;
				invalidCount++;
			}

			$error[validationErrorKey] = nValid;
			toggleValidCss($element, isValid, validationErrorKey);

			parentForm.$setValidity(validationErrorKey, isValid, this);
		};

		/**
		 * @vxdoc function
		 * @name vx.directive:vModel.vModelController#$setPristine
		 * @methodOf vx.directive:vModel.vModelController
		 *
		 * @description
		 * Sets the control to its pristine state.
		 *
		 * This method can be called to remove the 'v-dirty' class and set the control to its pristine
		 * state (v-pristine class).
		 */
		this.$setPristine = function() {
			this.$dirty = false;
			this.$pristine = true;
			$element.removeClass(DIRTY_CLASS).addClass(PRISTINE_CLASS);
		};

		this.$setDirty = function() {
			this.$dirty = true;
			this.$pristine = false;
			$element.removeClass(PRISTINE_CLASS).addClass(DIRTY_CLASS);
		};

		/**
		 * @vxdoc function
		 * @name vx.directive:vModel.vModelController#$setViewValue
		 * @methodOf vx.directive:vModel.vModelController
		 *
		 * @description
		 * Read a value from view.
		 *
		 * This method should be called from within a DOM event handler.
		 * For example {@link vx.directive:input input} or
		 * {@link vx.directive:select select} directives call it.
		 *
		 * It internally calls all `parsers` and if resulted value is valid, updates the model and
		 * calls all registered change listeners.
		 *
		 * @param {string} value Value from the view.
		 */
		this.$setViewValue = function(value) {
			this.$viewValue = value;

			// change to dirty
			if (this.$pristine) {
				this.$setDirty();
				if (parentCtrl)
					parentCtrl.$setDirty();
				parentForm.$setDirty();
			}

			forEach(this.$parsers, function(fn) {
				value = fn(value);
			});
			forEach(this.$$parsers, function(fn) {
				value = fnCall(fn, value);
			});

			if (this.$modelValue !== value) {
				this.$modelValue = value;
				vModelSet($scope, value);
				forEach(this.$viewChangeListeners, function(listener) {
					try {
						listener();
					} catch(e) {
						$log.error(formatError(e));
						//$exceptionHandler(e);
					}
				});
			}
		};
		// model -> value
		var ctrl = this;
		$scope.$watch(function vModelWatchAction() {
			var value = vModelGet($scope);
			// if scope model value and vModel value are out of sync
			var formatters = ctrl.$formatters, idx = formatters.length, modelChanged = ctrl.$modelValue !== value;
			if (modelChanged || ctrl.$virtual) {
				ctrl.$modelValue = value;
				while (idx--) {
					value = formatters[idx](value);
				}
			}

			formatters = ctrl.$$formatters, idx = formatters.length;
			while (idx--) {
				value = fnCall(formatters[idx], value);
			}

			if (ctrl.$virtual)// if virtual model, return value for watcher
				return value;

			if (modelChanged && ctrl.$viewValue !== value) {
				ctrl.$viewValue = value;
				ctrl.$render();
			}

		});

		function fnCall(fn, value) {
			var locals = {
				$scope : $scope,
				$value : value
			};
			// others inline dependency.
			return $injector.invoke(fn, null, locals);
		}

	}

	/**
	 * @vxdoc directive
	 * @name vx.directive:vModel
	 *
	 * @element input
	 *
	 * @description
	 * Is directive that tells VX to do two-way data binding. It works together with `input`,
	 * `select`, `textarea`. You can easily write your own directives to use `vModel` as well.
	 *
	 * `vModel` is responsible for:
	 *
	 * - binding the view into the model, which other directives such as `input`, `textarea` or `select`
	 *   require,
	 * - providing validation behavior (i.e. required, number, email, url),
	 * - keeping state of the control (valid/invalid, dirty/pristine, validation errors),
	 * - setting related css class onto the element (`v-valid`, `v-invalid`, `v-dirty`, `v-pristine`),
	 * - register the control with parent {@link vx.directive:form form}.
	 *
	 * For basic examples, how to use `vModel`, see:
	 *
	 *  - {@link vx.directive:input input}
	 *    - {@link vx.directive:input.text text}
	 *    - {@link vx.directive:input.checkbox checkbox}
	 *    - {@link vx.directive:input.radio radio}
	 *    - {@link vx.directive:input.number number}
	 *    - {@link vx.directive:input.email email}
	 *    - {@link vx.directive:input.url url}
	 *  - {@link vx.directive:select select}
	 *  - {@link vx.directive:textarea textarea}
	 *
	 */
	function vModelDirective() {
		return {
			require : ['vModel', '^?form'],
			controller : vModelController,
			link : function(scope, element, attr, ctrls) {
				// notify others, especially parent forms
				var modelCtrl = ctrls[0], formCtrl = ctrls[1] || nullFormCtrl;
				formCtrl.$addControl(modelCtrl, attr);
				element.bind('$destroy', function() {
					formCtrl.$removeControl(modelCtrl);
					modelCtrl.$destroy();
					cleanupClosure(modelCtrl);
				});
			}
		};
	}

	/**
	 * @vxdoc directive
	 * @name vx.directive:vChange
	 * @restrict E
	 *
	 * @description
	 * Evaluate given expression when user changes the input.
	 * The expression is not evaluated when the value change is coming from the model.
	 *
	 * Note, this directive requires `vModel` to be present.
	 *
	 * @element input
	 *
	 * @example
	 * <doc:example>
	 *   <doc:source>
	 *     <script>
	 *       function Controller($scope) {
	 *         $scope.counter = 0;
	 *         $scope.change = function() {
	 *           $scope.counter++;
	 *         };
	 *       }
	 *     </script>
	 *     <div v-controller="Controller">
	 *       <input type="checkbox" v-model="confirmed" v-change="change()" id="v-change-example1" />
	 *       <input type="checkbox" v-model="confirmed" id="v-change-example2" />
	 *       <label for="v-change-example2">Confirmed</label><br />
	 *       debug = {{confirmed}}<br />
	 *       counter = {{counter}}
	 *     </div>
	 *   </doc:source>
	 *   <doc:scenario>
	 *     it('should evaluate the expression if changing from view', function() {
	 *       expect(binding('counter')).toEqual('0');
	 *       element('#v-change-example1').click();
	 *       expect(binding('counter')).toEqual('1');
	 *       expect(binding('confirmed')).toEqual('true');
	 *     });
	 *
	 *     it('should not evaluate the expression if changing from model', function() {
	 *       element('#v-change-example2').click();
	 *       expect(binding('counter')).toEqual('0');
	 *       expect(binding('confirmed')).toEqual('true');
	 *     });
	 *   </doc:scenario>
	 * </doc:example>
	 */
	vChangeDirective.$inject = ['$$remote'];
	function vChangeDirective($$remote) {
		return {
			require : 'vModel',
			link : function(scope, element, attr, ctrl) {
				ctrl.$viewChangeListeners.push(function() {
					scope.$eval(attr.vChange, injectRemote(element, null, attr.vChange, false, $$remote));
				});
			}
		};
	}

	function requiredDirective() {
		function checkArray(data) {
			for (var i = 0; i < data.length; i++) {
				if (isValidItem(data[i])) {
					return true;
				}
			}
			return false;
		}

		return {
			require : '?vModel',
			link : function(scope, elm, attr, ctrl) {
				if (!ctrl)
					return;
				attr.required = true;
				// force truthy in case we are on non input element
				var validator = function(value) {
					if (attr.required && ((isArray(value) && !checkArray(value)) || (isEmpty(value) || value === false))) {
						ctrl.$setValidity('required', false);
						return null;
					} else {
						ctrl.$setValidity('required', true);
						return value;
					}
				};

				ctrl.$formatters.push(validator);
				ctrl.$parsers.unshift(validator);

				attr.$observe('required', function() {
					validator(ctrl.$viewValue);
				});

			}
		};
	}

	/**
	 * @vxdoc directive
	 * @name vx.directive:vList
	 *
	 * @description
	 * Text input that converts between comma-separated string into an array of strings.
	 *
	 * @element input
	 * @param {string=} vList optional delimiter that should be used to split the value. If
	 *   specified in form `/something/` then the value will be converted into a regular expression.
	 *
	 * @example
	 <doc:example>
	 <doc:source>
	 <script>
	 function Ctrl($scope) {
	 $scope.names = ['igor', 'misko', 'vojta'];
	 }
	 </script>
	 <form name="myForm" v-controller="Ctrl">
	 List: <input name="namesInput" v-model="names" v-list required>
	 <span class="error" v-show="myForm.list.$error.required">
	 Required!</span>
	 <tt>names = {{names}}</tt><br/>
	 <tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
	 <tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
	 <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
	 <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
	 </form>
	 </doc:source>
	 <doc:scenario>
	 it('should initialize to model', function() {
	 expect(binding('names')).toEqual('["igor","misko","vojta"]');
	 expect(binding('myForm.namesInput.$valid')).toEqual('true');
	 });

	 it('should be invalid if empty', function() {
	 input('names').enter('');
	 expect(binding('names')).toEqual('[]');
	 expect(binding('myForm.namesInput.$valid')).toEqual('false');
	 });
	 </doc:scenario>
	 </doc:example>
	 */
	/*
	function vListDirective() {
		return {
			require : 'vModel',
			link : function(scope, element, attr, ctrl) {
				var match = /\/(.*)\//.exec(attr.vList), separator = match && new RegExp(match[1]) || attr.vList || ',';

				var parse = function(viewValue) {
					var list = [];
					if (viewValue) {
						forEach(viewValue.split(separator), function(value) {
							if (value)
								list.push(trim(value));
						});
					}
					return list;
				};

				ctrl.$parsers.push(parse);
				ctrl.$formatters.push(function(value) {
					if (isArray(value)) {
						return value.join(', ');
					}
					return undefined;
				});
			}
		};
	}
	*/
	/*
	function vValueDirective() {
		var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
		return {
			priority : 100,
			compile : function(tpl, tplAttr) {
				if (CONSTANT_VALUE_REGEXP.test(tplAttr.vValue)) {
					return function(scope, elm, attr) {
						attr.$set('value', scope.$eval(attr.vValue));
					};
				} else {
					return function(scope, elm, attr) {
						scope.$watch(attr.vValue, function valueWatchAction(value) {
							attr.$set('value', value, false);
						});
					};
				}
			}
		};
	}
	*/

	/**
	 * @vxdoc directive
	 * @name vx.directive:select
	 * @restrict E
	 *
	 * @description
	 * HTML `SELECT` element with vx data-binding.
	 *
	 * # `vOptions`
	 *
	 * Optionally `vOptions` attribute can be used to dynamically generate a list of `<option>`
	 * elements for a `<select>` element using an array or an object obtained by evaluating the
	 * `vOptions` expression.
	 *˝˝
	 * When an item in the select menu is select, the value of array element or object property
	 * represented by the selected option will be bound to the model identified by the `vModel`
	 * directive of the parent select element.
	 *
	 * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
	 * be nested into the `<select>` element. This element will then represent `null` or "not selected"
	 * option. See example below for demonstration.
	 *
	 * Note: `vOptions` provides iterator facility for `<option>` element which should be used instead
	 * of {@link vx.directive:vRepeat vRepeat} when you want the
	 * `select` model to be bound to a non-string value. This is because an option element can currently
	 * be bound to string values only.
	 *
	 * @param {string} vModel Assignable vx expression to data-bind to.
	 * @param {string=} name Property name of the form under which the control is published.
	 * @param {string=} required The control is considered valid only if value is entered.
	 * @param {string=} vRequired Adds `required` attribute and `required` validation constraint to
	 *    the element when the vRequired expression evaluates to true. Use `vRequired` instead of
	 *    `required` when you want to data-bind to the `required` attribute.
	 * @param {comprehension_expression=} vOptions in one of the following forms:
	 *
	 *   * for array data sources:
	 *     * `label` **`for`** `value` **`in`** `array`
	 *     * `select` **`as`** `label` **`for`** `value` **`in`** `array`
	 *     * `label`  **`group by`** `group` **`for`** `value` **`in`** `array`
	 *     * `select` **`as`** `label` **`group by`** `group` **`for`** `value` **`in`** `array`
	 *     * `select` **`as`** `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
	 *   * for object data sources:
	 *     * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
	 *     * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
	 *     * `label` **`group by`** `group` **`for (`**`key`**`,`** `value`**`) in`** `object`
	 *     * `select` **`as`** `label` **`group by`** `group`
	 *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
	 *
	 * Where:
	 *
	 *   * `array` / `object`: an expression which evaluates to an array / object to iterate over.
	 *   * `value`: local variable which will refer to each item in the `array` or each property value
	 *      of `object` during iteration.
	 *   * `key`: local variable which will refer to a property name in `object` during iteration.
	 *   * `label`: The result of this expression will be the label for `<option>` element. The
	 *     `expression` will most likely refer to the `value` variable (e.g. `value.propertyName`).
	 *   * `select`: The result of this expression will be bound to the model of the parent `<select>`
	 *      element. If not specified, `select` expression will default to `value`.
	 *   * `group`: The result of this expression will be used to group options using the `<optgroup>`
	 *      DOM element.
	 *   * `trackexpr`: Used when working with an array of objects. The result of this expression will be
	 *      used to identify the objects in the array. The `trackexpr` will most likely refer to the
	 *     `value` variable (e.g. `value.propertyName`).
	 *
	 * @example
	 <doc:example>
	 <doc:source>
	 <script>
	 function MyCntrl($scope) {
	 $scope.colors = [
	 {name:'black', shade:'dark'},
	 {name:'white', shade:'light'},
	 {name:'red', shade:'dark'},
	 {name:'blue', shade:'dark'},
	 {name:'yellow', shade:'light'}
	 ];
	 $scope.color = $scope.colors[2]; // red
	 }
	 </script>
	 <div v-controller="MyCntrl">
	 <ul>
	 <li v-repeat="color in colors">
	 Name: <input v-model="color.name">
	 [<a href v-click="colors.splice($index, 1)">X</a>]
	 </li>
	 <li>
	 [<a href v-click="colors.push({})">add</a>]
	 </li>
	 </ul>
	 <hr/>
	 Color (null not allowed):
	 <select v-model="color" v-options="c.name for c in colors"></select><br>

	 Color (null allowed):
	 <span  class="nullable">
	 <select v-model="color" v-options="c.name for c in colors">
	 <option value="">-- chose color --</option>
	 </select>
	 </span><br/>

	 Color grouped by shade:
	 <select v-model="color" v-options="c.name group by c.shade for c in colors">
	 </select><br/>

	 Select <a href v-click="color={name:'not in list'}">bogus</a>.<br>
	 <hr/>
	 Currently selected: {{ {selected_color:color}  }}
	 <div style="border:solid 1px black; height:20px"
	 v-style="{'background-color':color.name}">
	 </div>
	 </div>
	 </doc:source>
	 <doc:scenario>
	 it('should check v-options', function() {
	 expect(binding('{selected_color:color}')).toMatch('red');
	 select('color').option('0');
	 expect(binding('{selected_color:color}')).toMatch('black');
	 using('.nullable').select('color').option('');
	 expect(binding('{selected_color:color}')).toMatch('null');
	 });
	 </doc:scenario>
	 </doc:example>
	 */
	selectDirective.$inject = ['$compile', '$parse'];
	function selectDirective($compile, $parse) {
		//0000111110000000000022220000000000000000000000333300000000000000444444444444444440000000005555555555555555500000006666666666666666600000000000000007777000000000000000000088888
		var V_OPTIONS_REGEXP = /^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w\d]*)|(?:\(\s*([\$\w][\$\w\d]*)\s*,\s*([\$\w][\$\w\d]*)\s*\)))\s+in\s+(.*?)(?:\s+track\s+by\s+(.*?))?$/, nullModelCtrl = {
			$setViewValue : noop
		};
		// we can't just jqLite('<option>') since jqLite is not smart enough
		// to create it in <select> and IE barfs otherwise.
		var optionTemplate = jqLite(document.createElement('option')), optGroupTemplate = jqLite(document.createElement('optgroup'));
		return {
			restrict : 'E',
			require : ['select', '?vModel'],
			controller : ['$element', '$scope', '$attrs',
			function($element, $scope, $attrs) {
				var self = this, optionsMap = {}, vModelCtrl = nullModelCtrl, nullOption, unknownOption;
				self.databound = $attrs.vModel;
				self.init = function(vModelCtrl_, nullOption_, unknownOption_) {
					vModelCtrl = vModelCtrl_;
					nullOption = nullOption_;
					unknownOption = unknownOption_;
				};

				self.addOption = function(value) {
					optionsMap[value] = true;
					if (vModelCtrl.$viewValue == value) {
						$element.val(value);
						if (unknownOption.parent())
							unknownOption.remove();
					}
				};

				self.removeOption = function(value) {
					if (this.hasOption(value)) {
						delete optionsMap[value];
						if (vModelCtrl.$viewValue == value) {
							this.renderUnknownOption(value);
						}
					}
				};

				self.renderUnknownOption = function(val) {
					var unknownVal = '? ' + hashKey(val) + ' ?';
					unknownOption.val(unknownVal);
					$element.prepend(unknownOption);
					$element.val(unknownVal);
					unknownOption.prop('selected', true);
					// needed for IE
				};

				self.hasOption = function(value) {
					return optionsMap.hasOwnProperty(value);
				};

				//$scope.$on('$destroy', function() {
				// disable unknown option so that we don't do work when the whole select is being destroyed
				//	self.renderUnknownOption = noop;
				//});

				$element.bind('$destroy', function() {
					cleanupClosure(self);
					if (msie)
						IE_GC(unknownOption[0]);
				});
			}],

			link : function(scope, element, attr, ctrls) {
				// if vModel is not defined, we don't need to do anything
				if (!ctrls[1])
					return;

				var selectCtrl = ctrls[0], vModelCtrl = ctrls[1], multiple = attr.multiple, optionsExp = attr.vOptions, nullOption = false, // if false, user will not be able to select it (used by vOptions)
				emptyOption, unknownOption = optionTemplate.clone();

				// find "null" option
				for (var i = 0, children = element.children(), ii = children.length; i < ii; i++) {
					if (children[i].value === '') {
						emptyOption = nullOption = jqLite(children[i]);
						break;
					}
				}

				selectCtrl.init(vModelCtrl, nullOption, unknownOption);

				// required validator
				if (multiple && (attr.required || attr.vRequired)) {
					var requiredValidator = function(value) {
						vModelCtrl.$setValidity('required', !attr.required || !!(value && value.length));
						return value;
					};

					vModelCtrl.$parsers.push(requiredValidator);
					vModelCtrl.$formatters.unshift(requiredValidator);

					attr.$observe('required', function() {
						requiredValidator(vModelCtrl.$viewValue);
					});
				}

				if (optionsExp)
					_Options(scope, element, vModelCtrl);
				else if (multiple)
					_Multiple(scope, element, vModelCtrl);
				else
					_Single(scope, element, vModelCtrl, selectCtrl);

				////////////////////////////

				function _Single(scope, selectElement, vModelCtrl, selectCtrl) {
					vModelCtrl.$render = function() {
						var viewValue = vModelCtrl.$viewValue;

						if (selectCtrl.hasOption(viewValue)) {
							if (unknownOption.parent())
								unknownOption.remove();
							selectElement.val(viewValue);
							if (viewValue === '')
								emptyOption.prop('selected', true);
							// to make IE9 happy
						} else {
							if (isUndefined(viewValue) && emptyOption) {
								selectElement.val('');
							} else {
								selectCtrl.renderUnknownOption(viewValue);
							}
						}
					};

					selectElement.bind('change', function() {
						scope.$apply(function() {
							if (unknownOption.parent())
								unknownOption.remove();
							vModelCtrl.$setViewValue(selectElement.val());
						}, ':select');
					});
				}

				function _Multiple(scope, selectElement, ctrl) {
					var lastView;
					ctrl.$render = function() {
						var items = new HashMap(ctrl.$viewValue);
						forEach(selectElement.find('option'), function(option) {
							option.selected = isDefined(items.get(option.value));
						});
					};
					// we have to do it on each watch since vModel watches reference, but
					// we need to work of an array, so we need to see if anything was inserted/removed
					scope.$watch(function selectMultipleWatch() {
						if (!equals(lastView, ctrl.$viewValue)) {
							lastView = copy(ctrl.$viewValue);
							ctrl.$render();
						}
					});

					selectElement.bind('change', function() {
						scope.$apply(function() {
							var array = [];
							forEach(selectElement.find('option'), function(option) {
								if (option.selected) {
									array.push(option.value);
								}
							});
							ctrl.$setViewValue(array);
						}, ':select');
					});
				}

				function _Options(scope, selectElement, ctrl) {
					var match;

					if (!( match = optionsExp.match(V_OPTIONS_REGEXP))) {
						throw vError(117, "vOptions error! Expected expression in form of '_select_ (as _label_)? for (_key_,)?_value_ in _collection_' but got '{0}'. Element: {1}", optionsExp, startingTag(selectElement));
					}

					var displayFn = $parse(match[2] || match[1]), valueName = match[4] || match[6], keyName = match[5], //
					groupByFn = $parse(match[3] || ''), valueFn = $parse(match[2] ? match[1] : valueName), valuesFn = $parse(match[7]), //
					track = match[8], trackFn = track ? $parse(match[8]) : null,
					// This is an array of array of existing option groups in DOM. We try to reuse these if possible
					// optionGroupsCache[0] is the options with no option group
					// optionGroupsCache[?][0] is the parent: either the SELECT or OPTGROUP element
					optionGroupsCache = [[{
						element : selectElement,
						label : ''
					}]];

					if (nullOption) {
						// compile the element since there might be bindings in it
						$compile(nullOption)(scope, null, false);

						// remove the class, which is added automatically because we recompile the element and it
						// becomes the compilation root
						//nullOption.removeClass('v-scope');

						// we need to remove it before calling selectElement.html('') because otherwise IE will
						// remove the label from the element. wtf?
						nullOption.remove();
					}

					// clear contents, we'll add what's needed based on the model
					selectElement.html('');

					selectElement.bind('change', function() {
						scope.$apply(function() {
							var optionGroup, collection = valuesFn(scope) || [], locals = {}, key, value, optionElement, index, groupIndex, length, groupLength, trackIndex;

							if (multiple) {
								value = [];
								for ( groupIndex = 0, groupLength = optionGroupsCache.length; groupIndex < groupLength; groupIndex++) {
									// list of options for that group. (first item has the parent)
									optionGroup = optionGroupsCache[groupIndex];

									for ( index = 1, length = optionGroup.length; index < length; index++) {
										if ((optionElement = optionGroup[index].element)[0].selected) {
											key = optionElement.val();
											if (keyName)
												locals[keyName] = key;
											if (trackFn) {
												for ( trackIndex = 0; trackIndex < collection.length; trackIndex++) {
													locals[valueName] = collection[trackIndex];
													if (trackFn(scope, locals) == key)
														break;
												}
											} else {
												locals[valueName] = collection[key];
											}
											value.push(valueFn(scope, locals));
										}
									}
								}
							} else {
								key = selectElement.val();
								if (key === '?') {
									value = undefined;
								} else if (key === '') {
									value = null;
								} else {
									if (trackFn) {
										for ( trackIndex = 0; trackIndex < collection.length; trackIndex++) {
											locals[valueName] = collection[trackIndex];
											if (trackFn(scope, locals) == key) {
												value = valueFn(scope, locals);
												break;
											}
										}
									} else {
										locals[valueName] = collection[key];
										if (keyName)
											locals[keyName] = key;
										value = valueFn(scope, locals);
									}
								}
							}
							ctrl.$setViewValue(value);
						}, ':select');
					});

					ctrl.$render = render;

					// TODO(vojta): can't we optimize this ?
					scope.$watch(render);

					function render() {
						var optionGroups = {
							'' : []
						}, // Temporary location for the option groups before we render them
						optionGroupNames = [''], optionGroupName, optionGroup, option, existingParent, existingOptions, //
						existingOption, modelValue = ctrl.$modelValue, values = valuesFn(scope) || [], keys = keyName ? sortedKeys(values) : values, //
						groupLength, length, groupIndex, index, locals = {}, selected, selectedSet = false, // nothing is selected yet
						lastElement, element;

						if (multiple) {
							if (trackFn && isArray(modelValue)) {
								selectedSet = new HashMap([]);
								for (var trackIndex = 0; trackIndex < modelValue.length; trackIndex++) {
									locals[valueName] = modelValue[trackIndex];
									selectedSet.put(trackFn(scope, locals), modelValue[trackIndex]);
								}
							} else {
								selectedSet = new HashMap(modelValue);
							}
						}

						// We now build up the list of options we need (we merge later)
						for ( index = 0, length = keys.length; index < length; index++) {
							locals[valueName] = values[ keyName ? locals[keyName] = keys[index] : index];
							optionGroupName = groupByFn(scope, locals) || '';
							if (!( optionGroup = optionGroups[optionGroupName])) {
								optionGroup = optionGroups[optionGroupName] = [];
								optionGroupNames.push(optionGroupName);
							}
							if (multiple) {
								selected = selectedSet.remove( trackFn ? trackFn(scope, locals) : valueFn(scope, locals)) !== undefined;
							} else {
								if (trackFn) {
									var modelCast = {};
									modelCast[valueName] = modelValue;
									selected = trackFn(scope, modelCast) === trackFn(scope, locals);
								} else {
									selected = modelValue === valueFn(scope, locals);
								}
								selectedSet = selectedSet || selected;
								// see if at least one item is selected
							}
							var displayLabel = displayFn(scope, locals);
							//*** modify by jimmy, for '0' or false
							optionGroup.push({
								id : trackFn ? trackFn(scope, locals) : ( keyName ? keys[index] : index), // either the index into array or key from object
								label : isEmpty(displayLabel) ? '' : displayLabel, // what will be seen by the user
								selected : selected // determine if we should be selected
							});
						}

						if (!multiple) {
							if (nullOption || modelValue === null) {
								// insert null option if we have a placeholder, or the model is null
								optionGroups[''].unshift({
									id : '',
									label : '',
									selected : !selectedSet
								});
							} else if (!selectedSet) {
								// option could not be found, we have to insert the undefined item
								optionGroups[''].unshift({
									id : '?',
									label : '',
									selected : true
								});
							}
						}

						// Now we need to update the list of DOM nodes to match the optionGroups we computed above
						for ( groupIndex = 0, groupLength = optionGroupNames.length; groupIndex < groupLength; groupIndex++) {
							// current option group name or '' if no group
							optionGroupName = optionGroupNames[groupIndex];

							// list of options for that group. (first item has the parent)
							optionGroup = optionGroups[optionGroupName];

							if (optionGroupsCache.length <= groupIndex) {
								// we need to grow the optionGroups
								existingParent = {
									element : optGroupTemplate.clone().attr('label', optionGroupName),
									label : optionGroup.label
								};
								existingOptions = [existingParent];
								optionGroupsCache.push(existingOptions);
								selectElement.append(existingParent.element);
							} else {
								existingOptions = optionGroupsCache[groupIndex];
								existingParent = existingOptions[0];
								// either SELECT (no group) or OPTGROUP element

								// update the OPTGROUP label if not the same.
								if (existingParent.label != optionGroupName) {
									existingParent.element.attr('label', existingParent.label = optionGroupName);
								}
							}
							lastElement = null;
							// start at the beginning
							for ( index = 0, length = optionGroup.length; index < length; index++) {
								option = optionGroup[index];
								if (( existingOption = existingOptions[index + 1])) {
									// reuse elements
									lastElement = existingOption.element;
									if (existingOption.label !== option.label) {
										lastElement.text(existingOption.label = option.label);
									}
									if (existingOption.id !== option.id) {
										lastElement.val(existingOption.id = option.id);
									}
									// lastElement.prop('selected') provided by jQuery has side-effects
									if (lastElement[0].selected !== option.selected) {
										lastElement.prop('selected', (existingOption.selected = option.selected));
									}
								} else {
									// grow elements

									// if it's a null option
									if (option.id === '' && nullOption) {
										// put back the pre-compiled element
										element = nullOption;
									} else {
										// jQuery(v1.4.2) Bug: We should be able to chain the method calls, but
										// in this version of jQuery on some browser the .text() returns a string
										// rather then the element.
										( element = optionTemplate.clone()).val(option.id).text(option.label);
										if (option.selected)
											element.attr('selected', option.selected);
										else
											element.removeAttr('selected');
									}

									existingOptions.push( existingOption = {
										element : element,
										label : option.label,
										id : option.id,
										selected : option.selected
									});
									if (lastElement) {
										lastElement.after(element);
									} else {
										existingParent.element.append(element);
									}
									lastElement = element;
								}
							}
							// remove any excessive OPTIONs in a group
							index++;
							// increment since the existingOptions[0] is parent element not OPTION
							while (existingOptions.length > index) {
								existingOptions.pop().element.remove();
							}
						}
						// remove any excessive OPTGROUPs from select
						while (optionGroupsCache.length > groupIndex) {
							optionGroupsCache.pop()[0].element.remove();
						}

						// for IE dynamic render bug
						//if (msie) {
						//	selectElement.css('display', 'none');
						//	selectElement.css('display', '');
						//}

						selectElement.bind('$destroy', function() {
							optionGroupsCache = [];
						});
					}

				}

			}
		};
	}

	function vOptionsDirective() {
		return {
			terminal : true
		};
	}

	// option directive
	optionDirective.$inject = ['$interpolate'];
	function optionDirective($interpolate) {
		var nullSelectCtrl = {
			addOption : noop,
			removeOption : noop
		};
		return {
			restrict : 'E',
			priority : 100,
			compile : function(element, attr) {
				if (isUndefined(attr.value)) {
					var interpolateFn = $interpolate(element.text(), true);
					if (!interpolateFn) {
						attr.$set('value', element.text());
					}
				}

				return function(scope, element, attr) {
					var selectCtrlName = '$selectController', parent = element.parent(), selectCtrl = parent.data(selectCtrlName) || parent.parent().data(selectCtrlName);
					// in case we are in optgroup

					if (selectCtrl && selectCtrl.databound) {
						// For some reason Opera defaults to true and if not overridden this messes up the repeater.
						// We don't want the view to drive the initialization of the model anyway.
						element.prop('selected', false);
					} else {
						selectCtrl = nullSelectCtrl;
					}

					if (interpolateFn) {
						scope.$watch(interpolateFn, function interpolateWatchAction(newVal, oldVal) {
							attr.$set('value', newVal);
							if (newVal !== oldVal)
								selectCtrl.removeOption(oldVal);
							selectCtrl.addOption(newVal);
						});
					} else {
						selectCtrl.addOption(attr.value);
					}

					element.bind('$destroy', function() {
						selectCtrl.removeOption(attr.value);
					});
				};
			}
		};
	}

	// v-val directive
	/*
	vValDirective.$inject = ['$validation', "$parse"];
	function vValDirective($validation, $parse) {
		function splitFn(str, ctrl) {
			var last = 0, length = str.length, type = 0, quot, colon = false, regex = false;
			for (var i = 0, ch, ch0; i < length; i++) {
				ch = str.charAt(i);
				// IE 6,7 cannot use str[i];
				if (ch === '\'' || ch === '"') {
					if (ch0 !== '\\') {
						if (!quot)
							quot = ch;
						else if (quot === ch)
							quot = undefined;
					}
				} else if (ch === '(') {
					if (!quot && !regex)
						colon = true;
				} else if (ch === ')') {
					if (!quot && !regex) {
						colon = false;
						type = 1;
					}
				} else if (ch === ',') {
					if (!colon && !regex) {
						useVal(type, trim(str.substring(last, i)), ctrl);
						last = i + 1;
						type = 0;
					}
				} else if (ch === '/') {
					if (!quot && ch0 !== '\\') {
						regex = !regex;
						if (!regex)
							type = 2;
					}
				}
				ch0 = ch;
			}
			useVal(type, trim(str.substring(last, length)), ctrl);
		}

		function useVal(type, fn, ctrl) {
			var alias;
			if (fn.charAt(0) === ':') {
				var i = type === 2 ? fn.indexOf('/') : fn.indexOf('(');
				alias = fn.substring(0, i);
				fn = fn.substring(i);
			}
			if (type === 2) {// direct regex
				return $validation.use(ctrl, alias || 'pattern', fn);
			} else {
				if (type === 1) {// for function call
					// normalize string's escape, need for $parse call string literal
					fn = fn.replace(/\\\\/g, '\\').replace(/\\/g, '\\\\');
				} else {// type === 0, for expression alias
					fn = fn + '()';
				}
				if (fn.charAt(0) === '(') {
					return $validation.use(ctrl, alias || 'evaluate', fn);
				}
				var f = $parse(fn)($validation.validators);
				if (f) {
					$validation.use(ctrl, f);
				} else {
					throw vError(118, 'no validator: {0}', fn);
				}
			}
		}

		return {
			require : 'vModel',
			link : function(scope, element, attr, ctrl) {
				var validateExpr = trim(attr.vVal);
				splitFn(validateExpr, ctrl);
			}
		};

	}*/

	// --- Directives End --- //